import { useCallback, useEffect, useMemo, useState } from "react"
import {
  DeleteOutlined,
  EditOutlined,
  ExperimentOutlined,
  LinkOutlined,
  ReloadOutlined,
  UploadOutlined,
} from "@ant-design/icons"
import {
  Alert,
  Button,
  Card,
  Checkbox,
  Col,
  Empty,
  Form,
  Input,
  InputNumber,
  Modal,
  Popconfirm,
  Row,
  Select,
  Space,
  Switch,
  Table,
  Tabs,
  Tag,
  Typography,
  Upload,
} from "antd"
import type { UploadProps } from "antd"
import { toast } from "../../utils/toast"
import type { BusinessSettingValue, FeaturePluginField } from "../api/settings"
import {
  deleteNotificationPlugin,
  disableNotificationPlugin,
  enableNotificationPlugin,
  getNotificationPluginConfig,
  installNotificationPlugin,
  listNotificationPlugins,
  previewNotificationPlugin,
  reloadNotificationPlugins,
  saveNotificationPluginConfig,
  testNotificationPlugin,
  type NotificationPlugin,
  type PluginTestResult,
} from "../api/notificationPlugins"

const { Title, Paragraph, Text } = Typography

const TYPE_LABEL: Record<string, string> = {
  email: "邮件",
  sms: "短信",
  verification: "实名认证",
  payment: "支付",
  auth: "第三方登录",
}

const CAPABILITY_LABEL: Record<string, string> = {
  email: "邮件发送",
  sms: "短信发送",
  verification: "实名认证",
  two_factor: "身份证二要素",
  three_factor: "三要素认证",
  face_api: "人脸识别接口",
  face_redirect: "H5 人脸核身",
  provision: "服务开通",
  payment: "支付处理",
  auth: "第三方登录",
}

const RUNTIME_LABEL: Record<string, string> = {
  "jsonrpc-stdio": "Go 进程插件（JSON-RPC）",
  process: "独立进程插件",
  builtin: "内置插件",
}

const VERIFICATION_MODE_LABEL: Record<string, string> = {
  two_factor: "二要素",
  three_factor: "三要素",
  face_redirect: "第三方 H5 跳转",
}

const CN_PHONE = /^1[3-9]\d{9}$/

function errorMessage(error: unknown, fallback: string) {
  const detail = (error as { response?: { data?: { detail?: string } } })?.response?.data?.detail
  if (detail) return detail
  if (error instanceof Error && error.message) return error.message
  return fallback
}

function capabilityLabel(value: string) {
  return CAPABILITY_LABEL[value] ?? value
}

function runtimeLabel(value?: string) {
  if (!value) return "未知"
  return RUNTIME_LABEL[value] ?? value
}

function renderFieldInput(field: FeaturePluginField) {
  if (field.type === "boolean") {
    return <Switch checkedChildren="启用" unCheckedChildren="关闭" />
  }
  if (field.type === "integer") {
    const validation = field.validation || {}
    return (
      <InputNumber
        min={typeof validation.min === "number" ? validation.min : undefined}
        max={typeof validation.max === "number" ? validation.max : undefined}
        precision={0}
        style={{ width: "100%" }}
        placeholder={field.placeholder}
      />
    )
  }
  if (field.type === "password" || field.secret) {
    return <Input.Password placeholder={field.placeholder} />
  }
  return <Input placeholder={field.placeholder} />
}

function fieldRules(field: FeaturePluginField) {
  const rules = []
  if (field.required) {
    rules.push({ required: true, message: `请输入${field.label}` })
  }
  rules.push({
    validator: (_: unknown, value: unknown) => {
      if (value === undefined || value === null || value === "") return Promise.resolve()
      const validation = field.validation || {}
      if (field.type === "email" && typeof value === "string" && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
        return Promise.reject(new Error("请输入有效邮箱"))
      }
      if (field.type === "integer") {
        const n = Number(value)
        if (!Number.isFinite(n)) return Promise.reject(new Error("请输入有效数字"))
        if (typeof validation.min === "number" && n < validation.min) return Promise.reject(new Error(`不能小于 ${validation.min}`))
        if (typeof validation.max === "number" && n > validation.max) return Promise.reject(new Error(`不能大于 ${validation.max}`))
      }
      if (typeof value === "string") {
        if (typeof validation.min_length === "number" && value.trim().length < validation.min_length) {
          return Promise.reject(new Error(`至少 ${validation.min_length} 个字符`))
        }
        if (typeof validation.max_length === "number" && value.length > validation.max_length) {
          return Promise.reject(new Error(`不能超过 ${validation.max_length} 个字符`))
        }
      }
      return Promise.resolve()
    },
  })
  return rules
}

function pluginConfigFields(plugin: NotificationPlugin | null | undefined) {
  return plugin?.config_fields?.length ? plugin.config_fields : (plugin?.config_schema?.fields ?? [])
}

type PluginPreview = NotificationPlugin & {
  exists?: boolean
  install_path?: string
  root_dir?: string
}

type PluginUploadStatus = "installing" | "success" | "failed" | "skipped"

interface PluginUploadItem {
  key: string
  file: File
  plugin?: PluginPreview
  previewing?: boolean
  previewError?: string
  installStatus?: PluginUploadStatus
  installError?: string
}

export default function AdminNotificationPlugins() {
  const [configForm] = Form.useForm<Record<string, BusinessSettingValue>>()
  const [testForm] = Form.useForm<{
    target?: string
    mode?: string
    real_name?: string
    id_card_no?: string
    phone?: string
    return_url?: string
  }>()
  const selectedTestMode = Form.useWatch("mode", testForm)
  const [plugins, setPlugins] = useState<NotificationPlugin[]>([])
  const [loading, setLoading] = useState(false)
  const [activeType, setActiveType] = useState<"email" | "sms" | "verification" | "payment" | "auth">("email")
  const [configPlugin, setConfigPlugin] = useState<NotificationPlugin | null>(null)
  const [testPlugin, setTestPlugin] = useState<NotificationPlugin | null>(null)
  const [testResult, setTestResult] = useState<PluginTestResult | null>(null)
  const [configValues, setConfigValues] = useState<Record<string, BusinessSettingValue>>({})
  const [savingConfig, setSavingConfig] = useState(false)
  const [testing, setTesting] = useState(false)
  const [switchingId, setSwitchingId] = useState<string | null>(null)
  const [uploading, setUploading] = useState(false)
  const [installing, setInstalling] = useState(false)
  const [uploadItems, setUploadItems] = useState<PluginUploadItem[]>([])
  const [overwriteExisting, setOverwriteExisting] = useState(false)
  const [applyingChanges, setApplyingChanges] = useState(false)

  const loadPlugins = useCallback(async () => {
    setLoading(true)
    try {
      const res = await listNotificationPlugins()
      setPlugins(res.data ?? [])
    } catch (error) {
      toast.error(errorMessage(error, "加载通知插件失败"))
    } finally {
      setLoading(false)
    }
  }, [])

  useEffect(() => {
    void loadPlugins()
  }, [loadPlugins])

  const grouped = useMemo(() => ({
    email: plugins.filter((item) => item.type === "email"),
    sms: plugins.filter((item) => item.type === "sms"),
    verification: plugins.filter((item) => item.type === "verification"),
    payment: plugins.filter((item) => item.type === "payment"),
    auth: plugins.filter((item) => item.type === "auth"),
  }), [plugins])

  const openConfig = async (plugin: NotificationPlugin) => {
    setConfigPlugin(plugin)
    setSavingConfig(false)
    try {
      const res = await getNotificationPluginConfig(plugin.type, plugin.id)
      const values = res.data?.values ?? {}
      setConfigValues(values)
      configForm.setFieldsValue(values)
    } catch (error) {
      toast.error(errorMessage(error, "读取插件配置失败"))
    }
  }

  const openTest = async (plugin: NotificationPlugin) => {
    setTestPlugin(plugin)
    setTestResult(null)
    testForm.resetFields()
    if (plugin.type === "verification") {
      const mode = plugin.capabilities?.includes("two_factor")
        ? "two_factor"
        : plugin.capabilities?.includes("three_factor")
          ? "three_factor"
          : "face_redirect"
      testForm.setFieldsValue({
        mode,
        return_url: `${window.location.origin}/settings?tab=verification`,
      })
    }
    try {
      const res = await getNotificationPluginConfig(plugin.type, plugin.id)
      const values = res.data?.values ?? {}
      setConfigValues(values)
      configForm.setFieldsValue(values)
    } catch (error) {
      toast.error(errorMessage(error, "读取插件配置失败"))
    }
  }

  const handleSaveConfig = async () => {
    if (!configPlugin) return
    let values: Record<string, BusinessSettingValue>
    try {
      values = await configForm.validateFields()
    } catch {
      return
    }
    setSavingConfig(true)
    try {
      await saveNotificationPluginConfig(configPlugin.type, configPlugin.id, values)
      toast.success("插件配置已保存")
      setConfigPlugin(null)
      await loadPlugins()
    } catch (error) {
      toast.error(errorMessage(error, "保存插件配置失败"))
    } finally {
      setSavingConfig(false)
    }
  }

  const handleToggle = async (plugin: NotificationPlugin, checked: boolean) => {
    setSwitchingId(plugin.id)
    try {
      if (checked) {
        await enableNotificationPlugin(plugin.type, plugin.id)
        toast.success(["payment", "auth"].includes(plugin.type) ? `${plugin.name} 已启用` : `已切换为 ${plugin.name}`)
      } else {
        await disableNotificationPlugin(plugin.type, plugin.id)
        toast.success(["payment", "auth"].includes(plugin.type) ? `${plugin.name} 已停用` : `${plugin.name} 已停止作为当前插件`)
      }
      await loadPlugins()
    } catch (error) {
      toast.error(errorMessage(error, checked ? "启用插件失败" : "禁用插件失败"))
    } finally {
      setSwitchingId(null)
    }
  }

  const handleTest = async () => {
    if (!testPlugin) return
    let formValues: {
      target?: string
      mode?: string
      real_name?: string
      id_card_no?: string
      phone?: string
      return_url?: string
    }
    try {
      formValues = await testForm.validateFields()
    } catch {
      return
    }
    setTesting(true)
    try {
      const res = await testNotificationPlugin(testPlugin.type, testPlugin.id, {
        ...formValues,
        values: configValues,
      })
      if (testPlugin.type === "verification") {
        setTestResult(res.data ?? null)
        toast.success(res.message || "实名认证插件测试已完成")
      } else {
        toast.success("测试发送已提交")
        setTestPlugin(null)
      }
    } catch (error) {
      toast.error(errorMessage(error, testPlugin.type === "verification" ? "实名认证插件测试失败" : "测试发送失败"))
    } finally {
      setTesting(false)
    }
  }

  const handleDelete = async (plugin: NotificationPlugin) => {
    try {
      await deleteNotificationPlugin(plugin.type, plugin.id)
      toast.success("插件已删除")
      await loadPlugins()
    } catch (error) {
      toast.error(errorMessage(error, "删除插件失败"))
    }
  }

  const closeUploadModal = () => {
    if (installing || uploading) return
    setUploadItems([])
    setOverwriteExisting(false)
  }

  const previewUploadFiles = async (files: readonly File[]) => {
    if (files.length === 0) return
    setUploading(true)
    setOverwriteExisting(false)
    try {
      const previews: PluginUploadItem[] = Array.from(files).map((file, index) => ({
        key: `${file.name}:${file.size}:${file.lastModified}:${index}`,
        file,
        previewing: true,
      }))
      setUploadItems(previews)

      let nextIndex = 0
      const previewNext = async () => {
        while (nextIndex < previews.length) {
          const index = nextIndex
          nextIndex += 1
          const item = previews[index]
          let result: PluginUploadItem
          try {
            const res = await previewNotificationPlugin(item.file)
            if (!res.data) {
              result = { ...item, previewing: false, previewError: "预览接口未返回插件信息" }
            } else {
              result = { ...item, previewing: false, plugin: res.data }
            }
          } catch (error) {
            result = { ...item, previewing: false, previewError: errorMessage(error, "插件包预览失败") }
          }
          previews[index] = result
          setUploadItems((items) => items.map((current) => (current.key === result.key ? result : current)))
        }
      }

      await Promise.all(Array.from({ length: Math.min(10, previews.length) }, () => previewNext()))

      const seen = new Map<string, string>()
      const normalized = previews.map((item) => {
        if (!item.plugin) return item
        const previous = seen.get(item.plugin.id)
        if (previous) {
          return { ...item, previewError: `同一批次中插件 ID 重复，已包含 ${previous}` }
        }
        seen.set(item.plugin.id, item.file.name)
        return item
      })
      setUploadItems(normalized)
      const validCount = normalized.filter((item) => item.plugin && !item.previewError).length
      if (validCount === 0) {
        toast.error("所选文件中没有可安装的插件包")
      }
    } finally {
      setUploading(false)
    }
  }

  const beforeUpload: UploadProps["beforeUpload"] = (file, fileList) => {
    if (file.uid === fileList[0]?.uid) {
      void previewUploadFiles(fileList)
    }
    return Upload.LIST_IGNORE
  }

  const updateUploadItem = (key: string, patch: Partial<PluginUploadItem>) => {
    setUploadItems((items) => items.map((item) => (item.key === key ? { ...item, ...patch } : item)))
  }

  const handleInstall = async () => {
    const pendingItems = uploadItems.filter((item) => item.plugin && !item.previewError && item.installStatus !== "success")
    if (pendingItems.length === 0) return
    setInstalling(true)
    let successCount = 0
    let failedCount = 0
    let skippedCount = 0

    for (const item of pendingItems) {
      const plugin = item.plugin!
      if (plugin.exists && !overwriteExisting) {
        skippedCount += 1
        updateUploadItem(item.key, { installStatus: "skipped", installError: "未开启覆盖安装" })
        continue
      }

      updateUploadItem(item.key, { installStatus: "installing", installError: undefined })
      try {
        await installNotificationPlugin(item.file, overwriteExisting)
        successCount += 1
        updateUploadItem(item.key, { installStatus: "success", installError: undefined })
      } catch (error) {
        failedCount += 1
        updateUploadItem(item.key, {
          installStatus: "failed",
          installError: errorMessage(error, "插件安装失败"),
        })
      }
    }

    try {
      if (successCount > 0) {
        await loadPlugins()
      }
      if (failedCount === 0 && skippedCount === 0) {
        toast.success(`批量安装完成，共安装 ${successCount} 个插件`)
        setUploadItems([])
        setOverwriteExisting(false)
      } else if (failedCount > 0) {
        toast.error(`批量安装完成：成功 ${successCount}，失败 ${failedCount}，跳过 ${skippedCount}`)
      } else {
        toast.info(`已安装 ${successCount} 个，跳过 ${skippedCount} 个已存在插件`)
      }
    } finally {
      setInstalling(false)
    }
  }

  const installableUploadCount = uploadItems.filter((item) => (
    item.plugin
    && !item.previewError
    && item.installStatus !== "success"
    && (!item.plugin.exists || overwriteExisting)
  )).length

  const uploadPreviewErrorCount = uploadItems.filter((item) => item.previewError).length

  const uploadColumns = [
    {
      title: "文件",
      width: 210,
      render: (_: unknown, item: PluginUploadItem) => (
        <Space orientation="vertical" size={2} style={{ maxWidth: 190 }}>
          <Text ellipsis={{ tooltip: item.file.name }}>{item.file.name}</Text>
          <Text type="secondary">{(item.file.size / 1024 / 1024).toFixed(2)} MB</Text>
          {item.previewError ? <Text type="danger">{item.previewError}</Text> : null}
        </Space>
      ),
    },
    {
      title: "插件",
      render: (_: unknown, item: PluginUploadItem) => item.plugin ? (
        <Space orientation="vertical" size={4}>
          <Space wrap>
            <Text strong>{item.plugin.name}</Text>
            <Tag>{TYPE_LABEL[item.plugin.type] ?? item.plugin.type}</Tag>
            <Tag>{item.plugin.version}</Tag>
          </Space>
          <Text type="secondary">{item.plugin.description}</Text>
        </Space>
      ) : <Text type="secondary">无法识别</Text>,
    },
    {
      title: "状态",
      width: 130,
      render: (_: unknown, item: PluginUploadItem) => {
        if (item.previewing) return <Tag color="processing">预览中</Tag>
        if (item.previewError) return <Tag color="red">预览失败</Tag>
        if (item.installStatus === "installing") return <Tag color="processing">安装中</Tag>
        if (item.installStatus === "success") return <Tag color="green">安装成功</Tag>
        if (item.installStatus === "failed") return <Tag color="red">安装失败</Tag>
        if (item.installStatus === "skipped") return <Tag color="orange">已跳过</Tag>
        return item.plugin?.exists ? <Tag color="orange">已存在</Tag> : <Tag color="green">可安装</Tag>
      },
    },
  ]

  const renderUploadDetails = (item: PluginUploadItem) => {
    if (!item.plugin) return null
    const fields = pluginConfigFields(item.plugin)
    return (
      <Space orientation="vertical" size={8} style={{ width: "100%" }}>
        <Space wrap>
          <Text type="secondary">运行时：{runtimeLabel(item.plugin.runtime)}</Text>
          <Text type="secondary">安装路径：{item.plugin.install_path || "-"}</Text>
        </Space>
        <Space wrap>
          <Text type="secondary">能力：</Text>
          {(item.plugin.capabilities ?? []).map((capability) => <Tag key={capability}>{capabilityLabel(capability)}</Tag>)}
        </Space>
        <Space wrap>
          <Text type="secondary">配置字段：</Text>
          {fields.map((field) => (
            <Tag color={field.required ? "blue" : "default"} key={field.key}>
              {field.label}{field.secret ? " / 密钥" : ""}
            </Tag>
          ))}
          {fields.length === 0 ? <Text type="secondary">无</Text> : null}
        </Space>
        <Text type="secondary">
          网络依赖：{item.plugin.requirements?.network?.join(", ") || "无"}
        </Text>
        {item.installError ? <Text type="danger">{item.installError}</Text> : null}
      </Space>
    )
  }

  const handleApplyChanges = async () => {
    setApplyingChanges(true)
    try {
      const res = await reloadNotificationPlugins({ install_dependencies: true, restart_backend: true })
      const packages = res.data?.dependencies.packages ?? []
      const pendingPackages = res.data?.dependencies.pending_packages ?? []
      const mode = res.data?.restart.mode ?? "none"
      toast.success(`插件变更已应用：依赖 ${packages.length} 个，需安装 ${pendingPackages.length} 个，重载模式 ${mode}`)
      await loadPlugins()
    } catch (error) {
      toast.error(errorMessage(error, "应用插件变更失败"))
    } finally {
      setApplyingChanges(false)
    }
  }

  const columns = [
    {
      title: "插件",
      dataIndex: "name",
      render: (_: unknown, plugin: NotificationPlugin) => (
        <Space orientation="vertical" size={4}>
          <Space wrap>
            <Text strong>{plugin.name}</Text>
            <Tag>{plugin.version}</Tag>
            <Tag color={plugin.enabled ? "green" : plugin.current ? "orange" : "default"}>
              {plugin.enabled
                ? (["payment", "auth"].includes(plugin.type) ? "已启用" : "当前使用")
                : plugin.current
                  ? "当前已停用"
                  : "可选"}
            </Tag>
            {plugin.protected ? <Tag color="gold">内置</Tag> : null}
          </Space>
          <Text type="secondary">{plugin.description}</Text>
          <Text code>插件标识：{plugin.provider}</Text>
        </Space>
      ),
    },
    {
      title: "能力",
      dataIndex: "capabilities",
      width: 260,
      render: (capabilities: string[]) => (
        <Space wrap>
          {(capabilities || []).map((item) => <Tag key={item}>{capabilityLabel(item)}</Tag>)}
        </Space>
      ),
    },
    {
      title: "业务状态",
      width: 116,
      render: (_: unknown, plugin: NotificationPlugin) => (
        <Space orientation="vertical" size={2}>
          <Switch
            checked={plugin.enabled}
            loading={switchingId === plugin.id}
            checkedChildren={["payment", "auth"].includes(plugin.type) ? "已启用" : "当前"}
            unCheckedChildren={["payment", "auth"].includes(plugin.type) ? "停用" : "选择"}
            onChange={(checked) => void handleToggle(plugin, checked)}
          />
          {!["payment", "auth"].includes(plugin.type) && !plugin.current ? <Text type="secondary">单选</Text> : null}
        </Space>
      ),
    },
    {
      title: "操作",
      width: 220,
      align: "right" as const,
      render: (_: unknown, plugin: NotificationPlugin) => (
        <Space>
          <Button
            icon={<ExperimentOutlined />}
            disabled={plugin.type !== "verification" && !plugin.test_supported}
            onClick={() => void openTest(plugin)}
          >
            测试
          </Button>
          <Button icon={<EditOutlined />} onClick={() => void openConfig(plugin)}>
            配置
          </Button>
          <Popconfirm
            title="删除插件"
            description={plugin.protected ? "内置插件不允许删除" : "删除后会移除该插件目录，确认继续？"}
            okText="删除"
            cancelText="取消"
            disabled={plugin.protected}
            onConfirm={() => void handleDelete(plugin)}
          >
            <Button danger icon={<DeleteOutlined />} disabled={plugin.protected}>
              删除
            </Button>
          </Popconfirm>
        </Space>
      ),
    },
  ]

  const renderTable = (type: "email" | "sms" | "verification" | "payment" | "auth") => (
    <Card variant="outlined">
      <Table
        rowKey={(record) => `${record.type}:${record.id}`}
        loading={loading}
        columns={columns}
        dataSource={grouped[type]}
        pagination={false}
        locale={{ emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={`暂无${TYPE_LABEL[type]}插件`} /> }}
      />
    </Card>
  )

  const configFields = pluginConfigFields(configPlugin)
  const isVerificationTest = testPlugin?.type === "verification"
  const verificationTestModes = (testPlugin?.capabilities ?? [])
    .filter((item) => ["two_factor", "three_factor", "face_redirect"].includes(item))
    .map((item) => ({ label: VERIFICATION_MODE_LABEL[item] ?? item, value: item }))

  return (
    <Space orientation="vertical" size={20} style={{ width: "100%" }}>
      <Row justify="space-between" align="bottom" gutter={[16, 16]}>
        <Col>
          <Title level={3} style={{ margin: 0 }}>功能插件</Title>
          <Paragraph type="secondary" style={{ marginTop: 8, marginBottom: 0 }}>
            管理邮件、短信、实名认证和支付插件。支付插件允许多个同时启用；配置字段来自插件自己的 plugin.json。
          </Paragraph>
        </Col>
        <Col>
          <Space>
            <Upload accept=".zip,.qplug" multiple showUploadList={false} beforeUpload={beforeUpload}>
              <Button icon={<UploadOutlined />} loading={uploading}>
                批量上传插件
              </Button>
            </Upload>
            <Popconfirm
              title="应用插件变更"
              description="将刷新插件清单，并按插件类型执行必要的依赖准备和后端重载。生产环境可配置 PLUGIN_RELOAD_COMMAND 接管重载流程。"
              okText="执行"
              cancelText="取消"
              onConfirm={() => void handleApplyChanges()}
            >
              <Button loading={applyingChanges}>
                应用插件变更
              </Button>
            </Popconfirm>
            <Button icon={<ReloadOutlined />} loading={loading} onClick={loadPlugins}>
              刷新
            </Button>
          </Space>
        </Col>
      </Row>

      <Tabs
        activeKey={activeType}
        onChange={(key) => setActiveType(key as "email" | "sms" | "verification" | "payment" | "auth")}
        items={[
          { key: "email", label: `邮件插件 (${grouped.email.length})`, children: renderTable("email") },
          { key: "sms", label: `短信插件 (${grouped.sms.length})`, children: renderTable("sms") },
          { key: "verification", label: `实名认证 (${grouped.verification.length})`, children: renderTable("verification") },
          { key: "payment", label: `支付插件 (${grouped.payment.length})`, children: renderTable("payment") },
          { key: "auth", label: `第三方登录 (${grouped.auth.length})`, children: renderTable("auth") },
        ]}
      />

      <Modal
        title={configPlugin ? `配置 ${configPlugin.name}` : "配置插件"}
        open={Boolean(configPlugin)}
        onCancel={() => setConfigPlugin(null)}
        onOk={handleSaveConfig}
        confirmLoading={savingConfig}
        width={760}
        destroyOnHidden
      >
        <Form form={configForm} layout="vertical" initialValues={configValues}>
          <Row gutter={[16, 0]}>
            {configFields.map((field) => (
              <Col xs={24} md={field.key.endsWith(".provider") ? 24 : 12} key={field.key}>
                <Form.Item
                  name={field.key}
                  label={field.label}
                  extra={field.help}
                  valuePropName={field.type === "boolean" ? "checked" : "value"}
                  rules={fieldRules(field)}
                >
                  {renderFieldInput(field)}
                </Form.Item>
              </Col>
            ))}
          </Row>
        </Form>
      </Modal>

      <Modal
        title={testPlugin ? `测试 ${testPlugin.name}` : "测试插件"}
        open={Boolean(testPlugin)}
        onCancel={() => { setTestPlugin(null); setTestResult(null) }}
        onOk={handleTest}
        confirmLoading={testing}
        width={720}
        destroyOnHidden
      >
        <Form form={testForm} layout="vertical">
          {isVerificationTest ? (
            <>
              <Row gutter={16}>
                <Col xs={24} md={12}>
                  <Form.Item name="mode" label="测试方式" rules={[{ required: true, message: "请选择测试方式" }]}>
                    <Select options={verificationTestModes} />
                  </Form.Item>
                </Col>
                <Col xs={24} md={12}>
                  <Form.Item name="real_name" label="姓名" rules={[{ required: true, message: "请输入姓名" }]}>
                    <Input placeholder="张三" />
                  </Form.Item>
                </Col>
              </Row>
              <Row gutter={16}>
                <Col xs={24} md={selectedTestMode === "three_factor" ? 12 : 24}>
                  <Form.Item name="id_card_no" label="身份证号" rules={[{ required: true, message: "请输入身份证号" }]}>
                    <Input placeholder="18 位身份证号" />
                  </Form.Item>
                </Col>
                {selectedTestMode === "three_factor" ? (
                  <Col xs={24} md={12}>
                    <Form.Item
                      name="phone"
                      label="手机号"
                      rules={[
                        { required: true, message: "请输入手机号" },
                        { pattern: CN_PHONE, message: "请输入有效国内手机号" },
                      ]}
                    >
                      <Input placeholder="11 位手机号" />
                    </Form.Item>
                  </Col>
                ) : null}
              </Row>
              {selectedTestMode === "face_redirect" ? (
                <Form.Item name="return_url" label="回跳地址" rules={[{ required: true, message: "请输入回跳地址" }]}>
                  <Input placeholder="https://example.com/verification-return" />
                </Form.Item>
              ) : null}
              <Text type="secondary">
                测试会使用该插件当前保存的配置；H5 测试会真实创建第三方核身链接。
              </Text>
            </>
          ) : (
            <>
              <Form.Item
                name="target"
                label={testPlugin?.type === "sms" ? "测试手机号" : "测试邮箱"}
                rules={[
                  { required: true, message: testPlugin?.type === "sms" ? "请输入测试手机号" : "请输入测试邮箱" },
                  testPlugin?.type === "sms"
                    ? { pattern: CN_PHONE, message: "请输入有效国内手机号" }
                    : { type: "email" as const, message: "请输入有效邮箱" },
                ]}
              >
                <Input placeholder={testPlugin?.type === "sms" ? "11 位手机号" : "test@example.com"} />
              </Form.Item>
              <Text type="secondary">
                测试会使用该插件当前保存的配置。短信测试会发送固定验证码 123456。
              </Text>
            </>
          )}

          {testResult ? (
            <Alert
              style={{ marginTop: 16 }}
              type={testResult.passed === false || testResult.status === "rejected" ? "warning" : "success"}
              showIcon
              title={testResult.url ? "H5 跳转测试链接已创建" : `测试结果：${testResult.status || (testResult.passed ? "通过" : "未通过")}`}
              description={(
                <Space orientation="vertical" size={6} style={{ width: "100%" }}>
                  {testResult.reason ? <Text>{testResult.reason}</Text> : null}
                  {testResult.url ? (
                    <Button icon={<LinkOutlined />} href={testResult.url} target="_blank" rel="noreferrer">
                      打开核身链接
                    </Button>
                  ) : null}
                  {testResult.external_id ? <Text type="secondary">外部流水：{testResult.external_id}</Text> : null}
                  {testResult.expires_in ? <Text type="secondary">有效期：{testResult.expires_in} 秒</Text> : null}
                </Space>
              )}
            />
          ) : null}
        </Form>
      </Modal>

      <Modal
        title={`批量安装插件${uploadItems.length > 0 ? ` (${uploadItems.length})` : ""}`}
        open={uploadItems.length > 0}
        onCancel={closeUploadModal}
        footer={[
          <Button key="cancel" disabled={installing || uploading} onClick={closeUploadModal}>
            关闭
          </Button>,
          <Button
            key="install"
            type="primary"
            loading={installing}
            disabled={installableUploadCount === 0}
            onClick={() => void handleInstall()}
          >
            安装 {installableUploadCount} 个插件
          </Button>,
        ]}
        width={960}
        closable={!installing && !uploading}
        maskClosable={!installing && !uploading}
        destroyOnHidden
      >
        <Space orientation="vertical" size={12} style={{ width: "100%" }}>
          {uploadPreviewErrorCount > 0 ? (
            <Alert
              type="warning"
              showIcon
              title={`${uploadPreviewErrorCount} 个文件预览失败，这些文件不会参与安装`}
            />
          ) : null}
          <Checkbox
            checked={overwriteExisting}
            disabled={installing || !uploadItems.some((item) => item.plugin?.exists)}
            onChange={(event) => setOverwriteExisting(event.target.checked)}
          >
            覆盖已存在的同名插件
          </Checkbox>
          <Table
            rowKey="key"
            size="small"
            columns={uploadColumns}
            dataSource={uploadItems}
            pagination={false}
            scroll={{ y: 430 }}
            expandable={{
              expandedRowRender: renderUploadDetails,
              rowExpandable: (item) => Boolean(item.plugin),
              defaultExpandAllRows: uploadItems.length === 1,
            }}
          />
        </Space>
      </Modal>
    </Space>
  )
}
