import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
import {
  Tabs,
  Card,
  Form,
  Select,
  Input,
  Button,
  Space,
  Divider,
  Tag,
  Modal,
  Switch,
  message,
  Avatar,
  Typography,
  Radio,
  Collapse,
} from "antd"
import { CloudOutlined, DatabaseOutlined } from "@ant-design/icons"
import { ThemeQuickSettings } from "./ThemeQuickSettings"
import { OAuthLogin } from "./OAuth/OAuthLogin"
import { SectlCloudSyncPanel } from "./SectlCloudSyncPanel"
import { SectlProvider } from "../contexts/SectlContext"
import { useTranslation } from "react-i18next"
import { pinyin } from "pinyin-pro"
import { changeLanguage, getCurrentLanguage, languageOptions, AppLanguage } from "../i18n"
import { useResponsive } from "../hooks/useResponsive"
import {
  buildSystemFontFamily,
  buildSystemFontValue,
  SYSTEM_FONT_STACK,
} from "../shared/fontFamily"

const { Text, Paragraph } = Typography

type permissionLevel = "admin" | "points" | "view"
type appSettings = {
  is_wizard_completed: boolean
  log_level: "debug" | "info" | "warn" | "error"
  window_zoom?: string
  search_keyboard_layout?: "t9" | "qwerty26"
  disable_search_keyboard?: boolean
  font_family?: string
}

interface FontOption {
  value: string
  label: string
  fontFamily: string
  searchText: string
}

const CHINESE_FONT_CHAR_PATTERN = /[\u3400-\u9fff]/
const CHINESE_FONT_SEGMENT_PATTERN = /[\u3400-\u9fff]+/g

const toPascalCasePinyin = (value: string): string =>
  pinyin(value, { toneType: "none" })
    .split(/\s+/)
    .filter(Boolean)
    .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase())
    .join("")

const formatFontDisplayName = (name: string): string => {
  if (!CHINESE_FONT_CHAR_PATTERN.test(name)) return name
  return name.replace(CHINESE_FONT_SEGMENT_PATTERN, (segment) => toPascalCasePinyin(segment))
}

const buildFontSearchText = (name: string, label: string): string =>
  `${name} ${label}`.toLowerCase()

const defaultFontOptions: FontOption[] = [
  {
    value: "system",
    label: "系统默认",
    fontFamily: SYSTEM_FONT_STACK,
    searchText: "系统默认 system default",
  },
]

const mergeFontOptions = (options: FontOption[]): FontOption[] => {
  const map = new Map<string, FontOption>()
  for (const option of options) {
    if (!map.has(option.value)) {
      map.set(option.value, option)
    }
  }
  return Array.from(map.values())
}

const findFontOption = (options: FontOption[], value?: string): FontOption | undefined => {
  if (!value) return options.find((item) => item.value === "system") || options[0]
  return (
    options.find((item) => item.value === value) || options.find((item) => item.value === "system")
  )
}

const applyFontFamily = (fontFamily: string) => {
  document.documentElement.style.setProperty("--ss-font-family", fontFamily)
  document.body.style.fontFamily = fontFamily
}
const withTimeout = async (
  promise: Promise<any>,
  ms: number,
  timeoutMessage: string
): Promise<any> => {
  let timer: ReturnType<typeof setTimeout> | undefined
  try {
    return await Promise.race<any>([
      promise,
      new Promise<any>((_, reject) => {
        timer = setTimeout(() => reject(new Error(timeoutMessage)), ms)
      }),
    ])
  } finally {
    if (timer) clearTimeout(timer)
  }
}

export const Settings: React.FC<{
  permission: permissionLevel
}> = ({ permission }) => {
  const { t } = useTranslation()
  const breakpoint = useResponsive()
  const isMobile = breakpoint === "xs" || breakpoint === "sm"
  const [activeTab, setActiveTab] = useState("appearance")
  const [currentLanguage, setCurrentLanguage] = useState<AppLanguage>(getCurrentLanguage())
  const [settings, setSettings] = useState<appSettings>({
    is_wizard_completed: false,
    log_level: "info",
    window_zoom: "1.0",
    search_keyboard_layout: "qwerty26",
    disable_search_keyboard: false,
  })
  const [fontOptions, setFontOptions] = useState<FontOption[]>(defaultFontOptions)
  const [isLoadingFonts, setIsLoadingFonts] = useState(false)
  const fontOptionsRef = useRef<FontOption[]>(defaultFontOptions)

  const [securityStatus, setSecurityStatus] = useState<{
    permission: permissionLevel
    hasAdminPassword: boolean
    hasPointsPassword: boolean
    hasRecoveryString: boolean
  } | null>(null)

  const [adminPassword, setAdminPassword] = useState("")
  const [pointsPassword, setPointsPassword] = useState("")
  const [recoveryToReset, setRecoveryToReset] = useState("")

  const [recoveryDialogVisible, setRecoveryDialogVisible] = useState(false)
  const [recoveryDialogHeader, setRecoveryDialogHeader] = useState("")
  const [recoveryDialogString, setRecoveryDialogString] = useState("")
  const [recoveryDialogFilename, setRecoveryDialogFilename] = useState("")

  const [aboutContent, setAboutContent] = useState<{
    title: string
    description: string
    content: string
    rawMarkdown: string
    version?: string
  } | null>(null)

  const [logsDialogVisible, setLogsDialogVisible] = useState(false)
  const [logsText, setLogsText] = useState("")
  const [logsLoading, setLogsLoading] = useState(false)

  const [clearDialogVisible, setClearDialogVisible] = useState(false)
  const [clearLoading, setClearLoading] = useState(false)

  const importInputRef = useRef<HTMLInputElement | null>(null)

  const [settleLoading, setSettleLoading] = useState(false)
  const [settleDialogVisible, setSettleDialogVisible] = useState(false)

  const [urlRegisterLoading, setUrlRegisterLoading] = useState(false)
  const [elevationStatus, setElevationStatus] = useState<{
    is_elevated: boolean
    platform: string
    can_request_elevation: boolean
  } | null>(null)
  const [elevationLoading, setElevationLoading] = useState(false)
  const [urlStatus, setUrlStatus] = useState<{
    registered: boolean
    protocol: string
    platform: string
    details: string
  } | null>(null)
  const [urlStatusLoading, setUrlStatusLoading] = useState(false)
  const [urlUnregisterLoading, setUrlUnregisterLoading] = useState(false)
  const [urlOperationLogs, setUrlOperationLogs] = useState<string[]>([])
  const [appQuitLoading, setAppQuitLoading] = useState(false)
  const [appRestartLoading, setAppRestartLoading] = useState(false)
  const [mcpLoading, setMcpLoading] = useState(false)
  const [mcpConfig, setMcpConfig] = useState<{ host: string; port: number }>({
    host: "127.0.0.1",
    port: 3901,
  })
  const [mcpStatus, setMcpStatus] = useState<{
    is_running: boolean
    config: { host: string; port: number }
    url?: string | null
  }>({
    is_running: false,
    config: { host: "127.0.0.1", port: 3901 },
    url: null,
  })
  const canAdmin = permission === "admin"
  const [messageApi, contextHolder] = message.useMessage()

  const [syncMethod, setSyncMethod] = useState<"postgresql" | "sectl_cloud">("postgresql")

  const [pgConnectionString, setPgConnectionString] = useState("")
  const [pgConnectionStatus, setPgConnectionStatus] = useState<{
    connected: boolean
    type: "sqlite" | "postgresql"
    error?: string
  }>({ connected: true, type: "sqlite" })
  const [pgTestLoading, setPgTestLoading] = useState(false)
  const [pgSwitchLoading, setPgSwitchLoading] = useState(false)
  const [pgUploadLoading, setPgUploadLoading] = useState(false)

  const [oauthLoginVisible, setOAuthLoginVisible] = useState(false)
  const [oauthUserInfo, setOAuthUserInfo] = useState<{
    user_id?: string
    id?: string
    email?: string
    name?: string
    avatar?: string
    avatar_url?: string
  } | null>(null)

  const permissionTag = useMemo(() => {
    return (
      <Tag
        color={permission === "admin" ? "success" : permission === "points" ? "warning" : "default"}
      >
        {permission === "admin"
          ? t("permissions.admin")
          : permission === "points"
            ? t("permissions.points")
            : t("permissions.view")}
      </Tag>
    )
  }, [permission, t])

  useEffect(() => {
    fontOptionsRef.current = fontOptions
  }, [fontOptions])

  const emitDataUpdated = (category: "events" | "students" | "reasons" | "all") => {
    window.dispatchEvent(new CustomEvent("ss:data-updated", { detail: { category } }))
  }

  const loadMcpStatus = async () => {
    if (!(window as any).api?.mcpServerStatus) return
    try {
      const res = await (window as any).api.mcpServerStatus()
      if (res.success && res.data) {
        setMcpStatus(res.data)
        if (res.data.config?.host && res.data.config?.port) {
          setMcpConfig({ host: res.data.config.host, port: res.data.config.port })
        }
      }
    } catch {
      // ignore status polling errors in settings page
    }
  }

  const loadSystemFonts = useCallback(
    async (selectedFontValue?: string) => {
      setIsLoadingFonts(true)

      const applySelectedFont = (options: FontOption[]) => {
        const current = findFontOption(options, selectedFontValue || settings.font_family)
        if (current) applyFontFamily(current.fontFamily)
      }

      const api = (window as any).api
      if (!api?.getSystemFonts) {
        setFontOptions(defaultFontOptions)
        applySelectedFont(defaultFontOptions)
        setIsLoadingFonts(false)
        return
      }

      try {
        const res = await api.getSystemFonts()
        if (res.success && Array.isArray(res.data)) {
          const remoteOptions = res.data
            .map((name: string) => String(name || "").trim())
            .filter((name: string) => Boolean(name))
            .map((name: string) => {
              const label = formatFontDisplayName(name)
              return {
                value: buildSystemFontValue(name),
                label,
                fontFamily: buildSystemFontFamily(name),
                searchText: buildFontSearchText(name, label),
              } satisfies FontOption
            })
            .sort((a: FontOption, b: FontOption) =>
              a.label.localeCompare(b.label, "zh-Hans-CN-u-co-pinyin")
            )

          const mergedOptions = mergeFontOptions([...defaultFontOptions, ...remoteOptions])
          setFontOptions(mergedOptions)
          applySelectedFont(mergedOptions)
        } else {
          setFontOptions(defaultFontOptions)
          applySelectedFont(defaultFontOptions)
        }
      } catch (error) {
        console.error("Failed to load system fonts:", error)
        setFontOptions(defaultFontOptions)
        applySelectedFont(defaultFontOptions)
      } finally {
        setIsLoadingFonts(false)
      }
    },
    [settings.font_family]
  )

  const loadAll = useCallback(async () => {
    const api = (window as any).api
    if (!api) {
      setFontOptions(defaultFontOptions)
      setIsLoadingFonts(false)
      return
    }

    let savedFontFamily = settings.font_family || "system"
    const res = await api.getAllSettings()
    if (res.success && res.data) {
      setSettings(res.data)
      setPgConnectionString(res.data.pg_connection_string || "")
      setPgConnectionStatus(res.data.pg_connection_status || { connected: true, type: "sqlite" })
      if (res.data.sync_method === "sectl_cloud") {
        setSyncMethod("sectl_cloud")
      } else {
        setSyncMethod("postgresql")
      }
      savedFontFamily = res.data.font_family || "system"
    }
    const authRes = await api.authGetStatus()
    if (authRes.success && authRes.data) setSecurityStatus(authRes.data)

    const oauthStateRes = await api.oauthLoadLoginState()
    if (oauthStateRes?.success && oauthStateRes.data) {
      setOAuthUserInfo({
        user_id: oauthStateRes.data.user_id,
        email: oauthStateRes.data.email,
        name: oauthStateRes.data.name,
      })
    } else {
      setOAuthUserInfo(null)
    }

    await loadMcpStatus()
    await loadSystemFonts(savedFontFamily)

    if (api.checkElevation) {
      try {
        const elevRes = await api.checkElevation()
        if (elevRes?.success && elevRes.data) {
          setElevationStatus(elevRes.data)
        }
      } catch {
        // ignore
      }
    }

    if (api.checkUrlProtocolStatus) {
      try {
        const urlRes = await api.checkUrlProtocolStatus()
        if (urlRes?.success && urlRes.data) {
          setUrlStatus(urlRes.data)
        }
      } catch {
        // ignore
      }
    }
  }, [settings, loadSystemFonts])

  const handleOAuthLogout = async () => {
    const api = (window as any).api
    if (!api) {
      setOAuthUserInfo(null)
      return
    }

    try {
      await api.oauthClearLoginState()
      setOAuthUserInfo(null)
      window.dispatchEvent(new CustomEvent("ss:oauth-user-updated", { detail: { user: null } }))
      messageApi.success(t("settings.account.logoutSuccess", "已退出云账号"))
    } catch (error: any) {
      messageApi.error(error?.message || t("common.error"))
    }
  }

  const handleRequestElevation = async () => {
    const api = (window as any).api
    if (!api?.requestElevation) return
    setElevationLoading(true)
    try {
      const res = await api.requestElevation()
      if (res?.success) {
        messageApi.success(t("settings.elevation.requestSuccess"))
      } else {
        messageApi.error(res?.message || t("settings.elevation.requestFailed"))
      }
    } catch (error: any) {
      messageApi.error(error?.message || t("settings.elevation.requestFailed"))
    } finally {
      setElevationLoading(false)
    }
  }

  const appendUrlLog = (msg: string) => {
    const ts = new Date().toLocaleTimeString()
    setUrlOperationLogs((prev) => [...prev.slice(-19), `[${ts}] ${msg}`])
  }

  const loadUrlStatus = async () => {
    const api = (window as any).api
    if (!api?.checkUrlProtocolStatus) return
    setUrlStatusLoading(true)
    try {
      const res = await api.checkUrlProtocolStatus()
      if (res?.success && res.data) {
        setUrlStatus(res.data)
      }
    } catch {
      // ignore
    } finally {
      setUrlStatusLoading(false)
    }
  }

  const handleUrlRegister = async () => {
    const api = (window as any).api
    if (!api?.registerUrlProtocol || !api?.checkUrlProtocolStatus) return
    setUrlRegisterLoading(true)
    appendUrlLog(t("settings.url.logRegisterStart"))

    const maxRetries = 7
    let success = false

    const doRegister = async () => {
      await api.registerUrlProtocol()
      appendUrlLog(t("settings.url.logRegisterVerify"))
      const statusRes = await api.checkUrlProtocolStatus()
      if (statusRes?.success && statusRes.data?.registered) {
        setUrlStatus(statusRes.data)
        return true
      }
      return false
    }

    success = await doRegister()

    if (!success) {
      for (let retry = 1; retry <= maxRetries; retry++) {
        appendUrlLog(t("settings.url.retrying", { current: retry, max: maxRetries }))
        await new Promise((r) => setTimeout(r, retry * 1000))
        success = await doRegister()
        if (success) {
          appendUrlLog(t("settings.url.retrySuccess", { n: retry }))
          break
        }
        appendUrlLog(t("settings.url.logRegisterFailed"))
      }
    }

    setUrlRegisterLoading(false)

    if (success) {
      appendUrlLog(t("settings.url.logRegisterSuccess"))
      messageApi.success(t("settings.url.registered"))
    } else {
      appendUrlLog(t("settings.url.logMaxRetries"))
      messageApi.error(t("settings.url.retryFailed"))
    }
  }

  const handleUrlUnregister = async () => {
    const api = (window as any).api
    if (!api?.unregisterUrlProtocol || !api?.checkUrlProtocolStatus) return
    setUrlUnregisterLoading(true)
    appendUrlLog(t("settings.url.logUnregisterStart"))

    try {
      const res = await api.unregisterUrlProtocol()
      if (res?.success) {
        const statusRes = await api.checkUrlProtocolStatus()
        if (statusRes?.success && statusRes.data) {
          setUrlStatus(statusRes.data)
        }
        appendUrlLog(t("settings.url.logUnregisterSuccess"))
        messageApi.success(t("settings.url.unregistered"))
      } else {
        appendUrlLog(t("settings.url.logUnregisterFailed"))
        messageApi.error(res?.message || t("settings.url.unregisterFailed"))
      }
    } catch (error: any) {
      appendUrlLog(t("settings.url.logUnregisterFailed"))
      messageApi.error(error?.message || t("settings.url.unregisterFailed"))
    } finally {
      setUrlUnregisterLoading(false)
    }
  }

  const loadAboutContent = async () => {
    try {
      const res = await fetch("/about-content.json")
      if (res.ok) {
        const data = await res.json()
        setAboutContent(data)
      }
    } catch {
      // ignore if about-content.json not found
    }
  }

  useEffect(() => {
    loadAll()
    loadAboutContent()
    const api = (window as any).api
    if (!api) return

    let disposed = false
    let unlisten: (() => void) | null = null

    api
      .onSettingChanged((change: any) => {
        setSettings((prev) => {
          if (change?.key === "log_level") return { ...prev, log_level: change.value }
          if (change?.key === "is_wizard_completed")
            return { ...prev, is_wizard_completed: change.value }
          if (change?.key === "window_zoom") return { ...prev, window_zoom: change.value }
          if (change?.key === "search_keyboard_layout")
            return { ...prev, search_keyboard_layout: change.value }
          if (change?.key === "disable_search_keyboard")
            return { ...prev, disable_search_keyboard: Boolean(change.value) }
          if (change?.key === "auto_score_enabled")
            return { ...prev, auto_score_enabled: change.value }
          if (change?.key === "font_family") {
            const value = String(change.value || "system")
            const fontOpt = findFontOption(fontOptionsRef.current, value)
            if (fontOpt) {
              applyFontFamily(fontOpt.fontFamily)
            }
            return { ...prev, font_family: value }
          }
          return prev
        })
      })
      .then((fn: () => void) => {
        if (disposed) {
          fn()
          return
        }
        unlisten = fn
      })
      .catch(() => void 0)

    return () => {
      disposed = true
      if (unlisten) unlisten()
    }
  }, [loadAll])

  useEffect(() => {
    const handleOAuthUserUpdated = (event: Event) => {
      const customEvent = event as CustomEvent<{
        user?: {
          user_id?: string
          email?: string
          name?: string
          github_username?: string
        } | null
      }>
      const user = customEvent?.detail?.user
      if (user?.user_id && user.email && user.name) {
        setOAuthUserInfo({
          user_id: user.user_id,
          email: user.email,
          name: user.name,
        })
      } else {
        setOAuthUserInfo(null)
      }
    }

    window.addEventListener("ss:oauth-user-updated", handleOAuthUserUpdated as EventListener)
    return () => {
      window.removeEventListener("ss:oauth-user-updated", handleOAuthUserUpdated as EventListener)
    }
  }, [])

  const showLogs = async () => {
    if (!(window as any).api) return
    setLogsLoading(true)
    const res = await (window as any).api.queryLogs(200)
    setLogsLoading(false)
    if (!res.success) {
      messageApi.error(res.message || t("settings.data.readLogsFailed"))
      return
    }
    setLogsText((res.data || []).join("\n"))
    setLogsDialogVisible(true)
  }

  const exportLogs = async () => {
    if (!(window as any).api) return
    const res = await (window as any).api.queryLogs(5000)
    if (!res.success) {
      messageApi.error(res.message || t("settings.data.readLogsFailed"))
      return
    }
    const dateTime = new Date().toISOString().replace(/[:.]/g, "-")
    downloadTextFile(`secscore_logs_${dateTime}.txt`, `${(res.data || []).join("\n")}\n`)
    messageApi.success(t("settings.data.logsExported"))
  }

  const downloadTextFile = (filename: string, text: string) => {
    const blob = new Blob(["\ufeff" + text], { type: "text/plain;charset=utf-8" })
    const url = URL.createObjectURL(blob)
    const a = document.createElement("a")
    a.href = url
    a.download = filename
    a.click()
    URL.revokeObjectURL(url)
  }

  const showRecoveryDialog = (header: string, recoveryString: string) => {
    const date = new Date().toISOString().slice(0, 10)
    const filename = `secscore_recovery_${date}.txt`
    setRecoveryDialogHeader(header)
    setRecoveryDialogString(recoveryString)
    setRecoveryDialogFilename(filename)
    setRecoveryDialogVisible(true)
  }

  const exportJson = async () => {
    if (!(window as any).api) return
    const res = await (window as any).api.exportDataJson()
    if (!res.success || !res.data) {
      messageApi.error(res.message || t("settings.data.exportFailed"))
      return
    }
    const blob = new Blob([res.data], { type: "application/json;charset=utf-8" })
    const url = URL.createObjectURL(blob)
    const a = document.createElement("a")
    a.href = url
    a.download = `secscore_export_${new Date().toISOString().slice(0, 10)}.json`
    a.click()
    URL.revokeObjectURL(url)
    messageApi.success(t("settings.data.exportSuccess"))
  }

  const importJson = async (file: File) => {
    if (!(window as any).api) return
    const text = await file.text()
    const res = await (window as any).api.importDataJson(text)
    if (res.success) {
      messageApi.success(t("settings.data.importSuccess"))
      setTimeout(() => window.location.reload(), 300)
    } else {
      messageApi.error(res.message || t("settings.data.importFailed"))
    }
  }

  const savePasswords = async () => {
    if (!(window as any).api) return
    const res = await (window as any).api.authSetPasswords({
      adminPassword: adminPassword ? adminPassword : undefined,
      pointsPassword: pointsPassword ? pointsPassword : undefined,
    })
    if (res.success) {
      setAdminPassword("")
      setPointsPassword("")
      await loadAll()
      if (res.data?.recoveryString) {
        showRecoveryDialog(
          t("settings.security.recoveryString") + ` (${t("recovery.hint")})`,
          res.data.recoveryString
        )
      } else {
        messageApi.success(t("settings.security.saved"))
      }
    } else {
      messageApi.error(res.message || t("settings.general.saveFailed"))
    }
  }

  const generateRecovery = async () => {
    if (!(window as any).api) return
    const res = await (window as any).api.authGenerateRecovery()
    if (!res.success || !res.data?.recoveryString) {
      messageApi.error(res.message || t("settings.security.generateFailed"))
      return
    }
    await loadAll()
    showRecoveryDialog(
      t("settings.security.newRecoveryString", "New recovery string (please save it)"),
      res.data.recoveryString
    )
  }

  const resetByRecovery = async () => {
    if (!(window as any).api) return
    const res = await (window as any).api.authResetByRecovery(recoveryToReset)
    if (!res.success || !res.data?.recoveryString) {
      messageApi.error(res.message || t("settings.security.resetFailed"))
      return
    }
    setRecoveryToReset("")
    await loadAll()
    showRecoveryDialog(
      t("settings.security.passwordClearedNewRecovery", "Password cleared, new recovery string"),
      res.data.recoveryString
    )
  }

  const clearAllPasswords = () => {
    setClearDialogVisible(true)
  }

  const handleConfirmClearAll = async () => {
    if (!(window as any).api) return
    setClearLoading(true)
    const res = await (window as any).api.authClearAll()
    setClearLoading(false)
    if (res.success) {
      messageApi.success(t("settings.security.cleared"))
      await loadAll()
      setClearDialogVisible(false)
    } else {
      messageApi.error(res.message || t("settings.security.clearFailed"))
    }
  }

  const confirmSettlement = () => {
    setSettleDialogVisible(true)
  }

  const testPgConnection = async () => {
    if (!(window as any).api) return
    if (!pgConnectionString) {
      messageApi.warning(t("settings.database.enterConnectionString"))
      return
    }
    setPgTestLoading(true)
    try {
      const res = await withTimeout(
        (window as any).api.dbTestConnection(pgConnectionString),
        20_000,
        "测试连接超时，请检查网络或连接字符串"
      )
      if (res.success && res.data?.success) {
        messageApi.success(t("settings.database.connectionTestSuccess"))
      } else {
        messageApi.error(
          res.data?.error || res.message || t("settings.database.connectionTestFailed")
        )
      }
    } catch (e: any) {
      messageApi.error(e?.message || t("settings.database.connectionTestFailed"))
    } finally {
      setPgTestLoading(false)
    }
  }

  const switchToPg = async () => {
    if (!(window as any).api) return
    if (!pgConnectionString.trim()) {
      messageApi.warning(t("settings.database.enterConnectionString"))
      return
    }
    setPgSwitchLoading(true)
    try {
      const res = await withTimeout(
        (window as any).api.dbSwitchConnection(pgConnectionString.trim()),
        25_000,
        "切换 PostgreSQL 超时，请检查网络或连接字符串"
      )
      if (res.success) {
        messageApi.success(
          t("settings.database.switchedTo", {
            type: res.data?.type === "postgresql" ? "PostgreSQL" : "SQLite",
          })
        )
        await loadAll()
      } else {
        messageApi.error(res.message || t("settings.database.switchFailed"))
      }
    } catch (e: any) {
      messageApi.error(e?.message || t("settings.database.switchFailed"))
    } finally {
      setPgSwitchLoading(false)
    }
  }

  const switchToSQLite = async () => {
    if (!(window as any).api) return
    setPgSwitchLoading(true)
    try {
      const res = await withTimeout(
        (window as any).api.dbSwitchConnection(""),
        15_000,
        "切换 SQLite 超时，请稍后重试"
      )
      if (res.success) {
        messageApi.success(t("settings.database.switchedToSQLite"))
        setPgConnectionString("")
        await loadAll()
      } else {
        messageApi.error(res.message || t("settings.database.switchFailed"))
      }
    } catch (e: any) {
      messageApi.error(e?.message || t("settings.database.switchFailed"))
    } finally {
      setPgSwitchLoading(false)
    }
  }

  const uploadLocalToRemote = async () => {
    if (!(window as any).api) return
    try {
      const statusRes = await (window as any).api.dbGetStatus()
      if (
        !statusRes.success ||
        !statusRes.data?.connected ||
        statusRes.data?.type !== "postgresql"
      ) {
        messageApi.warning(t("settings.database.uploadNeedRemote"))
        return
      }

      const previewRes = await withTimeout(
        (window as any).api.dbSyncPreview(),
        25_000,
        "同步预检查超时，请稍后重试"
      )
      if (!previewRes.success || !previewRes.data?.can_sync) {
        messageApi.error(
          previewRes.message || previewRes.data?.message || t("settings.database.uploadFailed")
        )
        return
      }
      if (!previewRes.data.need_sync) {
        messageApi.info(t("settings.database.noNeedUpload"))
        return
      }

      Modal.confirm({
        title: t("settings.database.uploadConfirmTitle"),
        content: t("settings.database.uploadConfirmContent", {
          localOnly: previewRes.data.local_only || 0,
          remoteOnly: previewRes.data.remote_only || 0,
          conflicts: previewRes.data.conflicts?.length || 0,
        }),
        okText: t("settings.database.uploadButton"),
        cancelText: t("common.cancel"),
        onOk: async () => {
          setPgUploadLoading(true)
          try {
            const applyRes = await withTimeout(
              (window as any).api.dbSyncApply("keep_local"),
              45_000,
              "执行同步超时，请稍后重试"
            )
            if (applyRes.success && applyRes.data?.success) {
              messageApi.success(applyRes.data?.message || t("settings.database.uploadSuccess"))
              emitDataUpdated("all")
              await loadAll()
            } else {
              messageApi.error(
                applyRes.data?.message || applyRes.message || t("settings.database.uploadFailed")
              )
            }
          } catch (e: any) {
            messageApi.error(e?.message || t("settings.database.uploadFailed"))
          } finally {
            setPgUploadLoading(false)
          }
        },
      })
    } catch (e: any) {
      messageApi.error(e?.message || t("settings.database.uploadFailed"))
    }
  }

  const startMcpServer = async () => {
    if (!(window as any).api?.mcpServerStart) return
    const host = mcpConfig.host.trim()
    const port = Number(mcpConfig.port)
    if (!host) {
      messageApi.warning(t("settings.mcp.hostRequired"))
      return
    }
    if (!Number.isInteger(port) || port <= 0 || port > 65535) {
      messageApi.warning(t("settings.mcp.portInvalid"))
      return
    }

    setMcpLoading(true)
    try {
      const res = await withTimeout(
        (window as any).api.mcpServerStart({ host, port }),
        10_000,
        t("settings.mcp.startTimeout")
      )
      if (res.success) {
        messageApi.success(t("settings.mcp.startSuccess"))
      } else {
        messageApi.error(res.message || t("settings.mcp.startFailed"))
      }
    } catch (e: any) {
      messageApi.error(e?.message || t("settings.mcp.startFailed"))
    } finally {
      await loadMcpStatus()
      setMcpLoading(false)
    }
  }

  const stopMcpServer = async () => {
    if (!(window as any).api?.mcpServerStop) return
    setMcpLoading(true)
    try {
      const res = await withTimeout(
        (window as any).api.mcpServerStop(),
        10_000,
        t("settings.mcp.stopTimeout")
      )
      if (res.success) {
        messageApi.success(t("settings.mcp.stopSuccess"))
      } else {
        messageApi.error(res.message || t("settings.mcp.stopFailed"))
      }
    } catch (e: any) {
      messageApi.error(e?.message || t("settings.mcp.stopFailed"))
    } finally {
      await loadMcpStatus()
      setMcpLoading(false)
    }
  }

  const currentYear = new Date().getFullYear()

  const confirmQuitApp = () => {
    Modal.confirm({
      title: t("settings.app.confirmQuitTitle"),
      content: t("settings.app.confirmQuitContent"),
      okText: t("settings.app.quit"),
      okButtonProps: { danger: true },
      cancelText: t("common.cancel"),
      onOk: async () => {
        if (!(window as any).api) return
        setAppQuitLoading(true)
        try {
          await (window as any).api.appQuit()
        } catch (e: any) {
          setAppQuitLoading(false)
          messageApi.error(e?.message || t("settings.app.quitFailed"))
        }
      },
    })
  }

  const confirmRestartApp = () => {
    Modal.confirm({
      title: t("settings.app.confirmRestartTitle"),
      content: t("settings.app.confirmRestartContent"),
      okText: t("settings.app.restart"),
      cancelText: t("common.cancel"),
      onOk: async () => {
        if (!(window as any).api) return
        setAppRestartLoading(true)
        try {
          await (window as any).api.appRestart()
        } catch (e: any) {
          setAppRestartLoading(false)
          messageApi.error(e?.message || t("settings.app.restartFailed"))
        }
      },
    })
  }

  const tabItems = [
    {
      key: "appearance",
      label: t("settings.tabs.appearance"),
      children: (
        <Card style={{ backgroundColor: "var(--ss-card-bg)", color: "var(--ss-text-main)" }}>
          <Form layout="horizontal" labelCol={{ span: 4 }} wrapperCol={{ span: 20 }}>
            <Form.Item label={t("settings.language")}>
              <Select
                value={currentLanguage}
                onChange={async (v: AppLanguage) => {
                  await changeLanguage(v)
                  setCurrentLanguage(v)
                  messageApi.success(t("common.success"))
                }}
                style={{ width: "320px" }}
                options={languageOptions.map((opt) => ({
                  value: opt.value,
                  label: opt.label,
                }))}
              />
              <div
                style={{ marginTop: "4px", fontSize: "12px", color: "var(--ss-text-secondary)" }}
              >
                {t("settings.languageHint")}
              </div>
            </Form.Item>
          </Form>

          <Divider />

          <ThemeQuickSettings />

          <Divider />

          <Form layout="horizontal" labelCol={{ span: 4 }} wrapperCol={{ span: 20 }}>
            <Form.Item label={t("settings.fontFamily")}>
              <Select
                value={settings.font_family || "system"}
                onChange={async (v) => {
                  const fontOpt = findFontOption(fontOptions, String(v))
                  if (!fontOpt) return
                  applyFontFamily(fontOpt.fontFamily)
                  setSettings((prev) => ({ ...prev, font_family: String(v) }))
                  if ((window as any).api) {
                    const res = await (window as any).api.setSetting("font_family", String(v))
                    if (res.success) {
                      messageApi.success(t("settings.general.saved"))
                    } else {
                      messageApi.error(res.message || t("settings.general.saveFailed"))
                    }
                  } else {
                    messageApi.success(t("settings.general.saved"))
                  }
                }}
                style={{ width: "320px" }}
                loading={isLoadingFonts}
                options={fontOptions.map((opt) => ({
                  value: opt.value,
                  label: opt.label,
                  searchText: opt.searchText,
                }))}
                showSearch
                filterOption={(input, option) =>
                  String(option?.searchText ?? option?.label ?? "")
                    .toLowerCase()
                    .includes(input.toLowerCase())
                }
              />
              <div
                style={{ marginTop: "4px", fontSize: "12px", color: "var(--ss-text-secondary)" }}
              >
                {t("settings.fontFamilyHint")}
              </div>
            </Form.Item>

            {!isMobile && (
              <>
                <Form.Item label={t("settings.searchKeyboard.title")}>
                  <Select
                    value={settings.search_keyboard_layout || "qwerty26"}
                    onChange={async (v) => {
                      if (!(window as any).api) return
                      const next = String(v) as "t9" | "qwerty26"
                      const res = await (window as any).api.setSetting(
                        "search_keyboard_layout",
                        next
                      )
                      if (res.success) {
                        setSettings((prev) => ({ ...prev, search_keyboard_layout: next }))
                        messageApi.success(t("settings.general.saved"))
                      } else {
                        messageApi.error(res.message || t("settings.general.saveFailed"))
                      }
                    }}
                    style={{ width: "320px" }}
                    disabled={!canAdmin}
                    options={[
                      { value: "qwerty26", label: t("settings.searchKeyboard.options.qwerty26") },
                      { value: "t9", label: t("settings.searchKeyboard.options.t9") },
                    ]}
                  />
                  <div
                    style={{
                      marginTop: "4px",
                      fontSize: "12px",
                      color: "var(--ss-text-secondary)",
                    }}
                  >
                    {t("settings.searchKeyboard.hint")}
                  </div>
                </Form.Item>

                <Form.Item label={t("settings.searchKeyboard.disableToggle")}>
                  <Switch
                    checked={Boolean(settings.disable_search_keyboard)}
                    onChange={async (checked) => {
                      if (!(window as any).api) return
                      const res = await (window as any).api.setSetting(
                        "disable_search_keyboard",
                        checked
                      )
                      if (res.success) {
                        setSettings((prev) => ({ ...prev, disable_search_keyboard: checked }))
                        messageApi.success(t("settings.general.saved"))
                      } else {
                        messageApi.error(res.message || t("settings.general.saveFailed"))
                      }
                    }}
                    disabled={!canAdmin}
                  />
                  <div
                    style={{
                      marginTop: "4px",
                      fontSize: "12px",
                      color: "var(--ss-text-secondary)",
                    }}
                  >
                    {t("settings.searchKeyboard.disableHint")}
                  </div>
                </Form.Item>
              </>
            )}

            <Form.Item label={t("settings.interfaceZoom")}>
              <Select
                value={settings.window_zoom || "1.0"}
                onChange={async (v) => {
                  if (!(window as any).api) return
                  const next = String(v)
                  const res = await (window as any).api.setSetting("window_zoom", next)
                  if (res.success) {
                    setSettings((prev) => ({ ...prev, window_zoom: next }))
                    messageApi.success(t("settings.general.saved"))
                  } else {
                    messageApi.error(res.message || t("settings.general.saveFailed"))
                  }
                }}
                style={{ width: "320px" }}
                disabled={!canAdmin}
                options={[
                  { value: "0.7", label: t("settings.zoomOptions.small70") },
                  { value: "0.8", label: "80%" },
                  { value: "0.9", label: "90%" },
                  { value: "1.0", label: t("settings.zoomOptions.default100") },
                  { value: "1.1", label: "110%" },
                  { value: "1.2", label: "120%" },
                  { value: "1.3", label: "130%" },
                  { value: "1.5", label: t("settings.zoomOptions.large150") },
                ]}
              />
              <div
                style={{ marginTop: "4px", fontSize: "12px", color: "var(--ss-text-secondary)" }}
              >
                {t("settings.zoomHint")}
              </div>
            </Form.Item>
          </Form>
        </Card>
      ),
    },
    {
      key: "security",
      label: t("settings.tabs.security"),
      children: (
        <>
          <Card
            style={{
              backgroundColor: "var(--ss-card-bg)",
              color: "var(--ss-text-main)",
              marginBottom: "16px",
            }}
          >
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
              <div style={{ fontWeight: 600 }}>{t("settings.security.title")}</div>
              <Space>
                <Tag color={securityStatus?.hasAdminPassword ? "success" : "default"}>
                  {t("settings.security.adminPassword")}{" "}
                  {securityStatus?.hasAdminPassword
                    ? t("settings.security.set")
                    : t("settings.security.notSet")}
                </Tag>
                <Tag color={securityStatus?.hasPointsPassword ? "success" : "default"}>
                  {t("settings.security.pointsPassword")}{" "}
                  {securityStatus?.hasPointsPassword
                    ? t("settings.security.set")
                    : t("settings.security.notSet")}
                </Tag>
                <Tag color={securityStatus?.hasRecoveryString ? "success" : "default"}>
                  {t("settings.security.recoveryString")}{" "}
                  {securityStatus?.hasRecoveryString
                    ? t("settings.security.generated")
                    : t("settings.security.notGenerated")}
                </Tag>
              </Space>
            </div>

            <Divider />

            <Form layout="horizontal" labelCol={{ span: 4 }} wrapperCol={{ span: 20 }}>
              <Form.Item label={t("settings.security.adminPassword")}>
                <Input
                  value={adminPassword}
                  onChange={(e) => setAdminPassword(e.target.value)}
                  placeholder={t("settings.security.adminPasswordPlaceholder")}
                  maxLength={6}
                  disabled={!canAdmin && Boolean(securityStatus?.hasAdminPassword)}
                />
              </Form.Item>

              <Form.Item label={t("settings.security.pointsPassword")}>
                <Input
                  value={pointsPassword}
                  onChange={(e) => setPointsPassword(e.target.value)}
                  placeholder={t("settings.security.pointsPasswordPlaceholder")}
                  maxLength={6}
                  disabled={!canAdmin && Boolean(securityStatus?.hasAdminPassword)}
                />
              </Form.Item>

              <Form.Item label={t("common.operation")}>
                <Space>
                  <Button
                    type="primary"
                    onClick={savePasswords}
                    disabled={!canAdmin && Boolean(securityStatus?.hasAdminPassword)}
                  >
                    {t("settings.security.savePassword")}
                  </Button>
                  <Button
                    onClick={generateRecovery}
                    disabled={!canAdmin && Boolean(securityStatus?.hasAdminPassword)}
                  >
                    {t("settings.security.generateRecovery")}
                  </Button>
                  <Button danger onClick={clearAllPasswords} disabled={!canAdmin}>
                    {t("settings.security.clearAllPasswords")}
                  </Button>
                </Space>
              </Form.Item>
            </Form>
          </Card>

          <Card style={{ backgroundColor: "var(--ss-card-bg)", color: "var(--ss-text-main)" }}>
            <div style={{ fontWeight: 600, marginBottom: "12px" }}>
              {t("settings.security.recoveryReset")}
            </div>
            <Space>
              <Input
                value={recoveryToReset}
                onChange={(e) => setRecoveryToReset(e.target.value)}
                placeholder={t("settings.security.recoveryPlaceholder")}
                style={{ width: "420px" }}
              />
              <Button type="primary" onClick={resetByRecovery}>
                {t("settings.security.resetPassword")}
              </Button>
            </Space>
            <div style={{ marginTop: "8px", fontSize: "12px", color: "var(--ss-text-secondary)" }}>
              {t("settings.security.resetHint")}
            </div>
          </Card>
        </>
      ),
    },
    {
      key: "account",
      label: t("settings.tabs.account"),
      children: (
        <>
          <Card
            style={{
              backgroundColor: "var(--ss-card-bg)",
              color: "var(--ss-text-main)",
              marginBottom: "16px",
            }}
          >
            <div style={{ fontWeight: 600, marginBottom: "16px" }}>
              {t("settings.account.title")}
            </div>

            {oauthUserInfo ? (
              <div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
                <div style={{ display: "flex", alignItems: "center", gap: "16px" }}>
                  <Avatar
                    size={64}
                    src={oauthUserInfo.avatar || oauthUserInfo.avatar_url}
                    style={{ backgroundColor: "#1890ff" }}
                  >
                    {(oauthUserInfo.name || "U").charAt(0).toUpperCase()}
                  </Avatar>
                  <div>
                    <div style={{ fontSize: "18px", fontWeight: 600 }}>{oauthUserInfo.name}</div>
                    <div style={{ fontSize: "14px", color: "var(--ss-text-secondary)" }}>
                      {oauthUserInfo.email}
                    </div>
                  </div>
                </div>

                <Divider />

                <div>
                  <Text type="secondary">{t("settings.account.userId")}:</Text>
                  <Text code style={{ marginLeft: "8px" }}>
                    {oauthUserInfo.user_id || oauthUserInfo.id}
                  </Text>
                </div>

                <Divider />

                <Button danger onClick={handleOAuthLogout}>
                  {t("settings.account.logout")}
                </Button>
              </div>
            ) : (
              <div style={{ textAlign: "center", padding: "20px 0" }}>
                <Paragraph style={{ color: "var(--ss-text-secondary)" }}>
                  {t("settings.account.notLoggedIn")}
                </Paragraph>
                <Paragraph style={{ color: "var(--ss-text-secondary)", fontSize: "13px" }}>
                  {t("settings.account.oauthHint")}
                </Paragraph>
                <Button type="primary" size="large" onClick={() => setOAuthLoginVisible(true)}>
                  {t("settings.account.loginButton")}
                </Button>
              </div>
            )}
          </Card>
        </>
      ),
    },
    {
      key: "database",
      label: t("settings.cloudSync.title"),
      children: (
        <>
          <Card
            style={{
              backgroundColor: "var(--ss-card-bg)",
              color: "var(--ss-text-main)",
              marginBottom: "16px",
            }}
          >
            <div style={{ fontWeight: 600, marginBottom: "12px" }}>
              {t("settings.cloudSync.selectMethod")}
            </div>
            <div
              style={{ marginBottom: "16px", fontSize: "12px", color: "var(--ss-text-secondary)" }}
            >
              {t("settings.cloudSync.selectMethodHint")}
            </div>
            <Radio.Group
              value={syncMethod}
              onChange={async (e) => {
                const next = e.target.value as "postgresql" | "sectl_cloud"
                setSyncMethod(next)
                if ((window as any).api) {
                  await (window as any).api.setSetting("sync_method", next)
                }
              }}
              disabled={!canAdmin}
              style={{ width: "100%" }}
            >
              <Space direction="vertical" style={{ width: "100%" }} size={12}>
                <Card
                  hoverable
                  size="small"
                  style={{
                    borderColor:
                      syncMethod === "postgresql" ? "var(--ant-color-primary)" : undefined,
                    backgroundColor:
                      syncMethod === "postgresql" ? "var(--ant-color-primary-bg)" : undefined,
                  }}
                >
                  <Radio
                    value="postgresql"
                    styles={{
                      root: { width: "100%", alignItems: "center" },
                      label: { display: "flex", alignItems: "center", flex: 1, gap: 8 },
                    }}
                  >
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontWeight: 500 }}>{t("settings.cloudSync.postgresql")}</div>
                      <div
                        style={{
                          fontSize: "12px",
                          color: "var(--ss-text-secondary)",
                          marginTop: 4,
                        }}
                      >
                        {t("settings.cloudSync.postgresqlDesc")}
                      </div>
                    </div>
                    <DatabaseOutlined
                      style={{
                        fontSize: "26px",
                        color: "var(--ant-color-primary)",
                        flexShrink: 0,
                      }}
                    />
                  </Radio>
                </Card>
                <Card
                  hoverable
                  size="small"
                  style={{
                    borderColor:
                      syncMethod === "sectl_cloud" ? "var(--ant-color-primary)" : undefined,
                    backgroundColor:
                      syncMethod === "sectl_cloud" ? "var(--ant-color-primary-bg)" : undefined,
                  }}
                >
                  <Radio
                    value="sectl_cloud"
                    styles={{
                      root: { width: "100%", alignItems: "center" },
                      label: { display: "flex", alignItems: "center", flex: 1, gap: 8 },
                    }}
                  >
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontWeight: 500 }}>{t("settings.cloudSync.sectlCloud")}</div>
                      <div
                        style={{
                          fontSize: "12px",
                          color: "var(--ss-text-secondary)",
                          marginTop: 4,
                        }}
                      >
                        {t("settings.cloudSync.sectlCloudDesc")}
                      </div>
                    </div>
                    <CloudOutlined
                      style={{
                        fontSize: "26px",
                        color: "var(--ant-color-primary)",
                        flexShrink: 0,
                      }}
                    />
                  </Radio>
                </Card>
              </Space>
            </Radio.Group>
          </Card>

          {syncMethod === "postgresql" ? (
            <>
              <Card
                style={{
                  backgroundColor: "var(--ss-card-bg)",
                  color: "var(--ss-text-main)",
                  marginBottom: "16px",
                }}
              >
                <div style={{ fontWeight: 600, marginBottom: "12px" }}>
                  {t("settings.database.currentStatus")}
                </div>
                <Space>
                  <Tag color={pgConnectionStatus.type === "postgresql" ? "blue" : "green"}>
                    {pgConnectionStatus.type === "postgresql"
                      ? t("settings.database.postgresqlRemote")
                      : t("settings.database.sqliteLocal")}
                  </Tag>
                  <Tag color={pgConnectionStatus.connected ? "success" : "error"}>
                    {pgConnectionStatus.connected
                      ? t("settings.database.connected")
                      : t("settings.database.disconnected")}
                  </Tag>
                  {pgConnectionStatus.error && (
                    <span style={{ color: "var(--ant-color-error, #ff4d4f)", fontSize: "12px" }}>
                      {pgConnectionStatus.error}
                    </span>
                  )}
                </Space>
              </Card>

              <Card
                style={{
                  backgroundColor: "var(--ss-card-bg)",
                  color: "var(--ss-text-main)",
                  marginBottom: "16px",
                }}
              >
                <div style={{ fontWeight: 600, marginBottom: "12px" }}>
                  {t("settings.database.postgresqlConnection")}
                </div>
                <div
                  style={{
                    marginBottom: "12px",
                    fontSize: "12px",
                    color: "var(--ss-text-secondary)",
                  }}
                >
                  {t("settings.database.connectionHint")}
                </div>
                <Space.Compact style={{ width: "100%", marginBottom: "12px" }}>
                  <Input
                    value={pgConnectionString}
                    onChange={(e) => setPgConnectionString(e.target.value)}
                    placeholder="postgresql://user:password@host:port/database?sslmode=require"
                    style={{ flex: 1 }}
                    disabled={!canAdmin}
                  />
                  <Button
                    onClick={testPgConnection}
                    loading={pgTestLoading}
                    disabled={!canAdmin || !pgConnectionString}
                  >
                    {t("settings.database.testConnection")}
                  </Button>
                </Space.Compact>
                <div
                  style={{
                    marginBottom: "12px",
                    fontSize: "12px",
                    color: "var(--ss-text-secondary)",
                  }}
                >
                  {t("settings.database.connectionExample")}
                </div>
                <Space
                  direction={isMobile ? "vertical" : "horizontal"}
                  size={isMobile ? 8 : "small"}
                  style={{ width: "100%" }}
                >
                  <Button
                    type="primary"
                    onClick={switchToPg}
                    loading={pgSwitchLoading}
                    disabled={!canAdmin || !pgConnectionString}
                    style={{ width: isMobile ? "100%" : "auto" }}
                  >
                    {t("settings.database.switchToPostgreSQL")}
                  </Button>
                  <Button
                    onClick={switchToSQLite}
                    loading={pgSwitchLoading}
                    disabled={!canAdmin || pgConnectionStatus.type === "sqlite"}
                    style={{ width: isMobile ? "100%" : "auto" }}
                  >
                    {t("settings.database.switchToSQLite")}
                  </Button>
                  <Button
                    onClick={uploadLocalToRemote}
                    loading={pgUploadLoading}
                    disabled={!canAdmin || pgConnectionStatus.type !== "postgresql"}
                    style={{ width: isMobile ? "100%" : "auto" }}
                  >
                    {t("settings.database.uploadButton")}
                  </Button>
                </Space>
                <div
                  style={{ marginTop: "8px", fontSize: "12px", color: "var(--ss-text-secondary)" }}
                >
                  {t("settings.database.uploadHint")}
                </div>
              </Card>

              <Card style={{ backgroundColor: "var(--ss-card-bg)", color: "var(--ss-text-main)" }}>
                <div style={{ fontWeight: 600, marginBottom: "12px" }}>
                  {t("settings.database.syncDescription")}
                </div>
                <div
                  style={{
                    fontSize: "13px",
                    color: "var(--ss-text-secondary)",
                    lineHeight: "1.8",
                  }}
                >
                  <p>{t("settings.database.syncPoint1")}</p>
                  <p>{t("settings.database.syncPoint2")}</p>
                  <p>{t("settings.database.syncPoint3")}</p>
                  <p>{t("settings.database.syncPoint4")}</p>
                </div>
              </Card>
            </>
          ) : (
            <SectlProvider>
              <SectlCloudSyncPanel />
            </SectlProvider>
          )}
        </>
      ),
    },
    {
      key: "data",
      label: t("settings.data.title"),
      children: (
        <>
          <Card
            title={t("settings.data.settlement")}
            style={{
              backgroundColor: "var(--ss-card-bg)",
              color: "var(--ss-text-main)",
              marginBottom: "16px",
            }}
          >
            <Space align="center">
              <Button
                danger
                disabled={!canAdmin}
                loading={settleLoading}
                onClick={confirmSettlement}
              >
                {t("settings.data.settlementAndRestart")}
              </Button>
              <div style={{ fontSize: "12px", color: "var(--ss-text-secondary)" }}>
                {t("settings.data.settlementHint")}
              </div>
            </Space>
          </Card>

          <Card
            style={{
              backgroundColor: "var(--ss-card-bg)",
              color: "var(--ss-text-main)",
              marginBottom: "16px",
            }}
          >
            <div style={{ fontWeight: 600, marginBottom: "12px" }}>
              {t("settings.data.importExport")}
            </div>
            <Space>
              <Button type="primary" onClick={exportJson}>
                {t("settings.data.exportJson")}
              </Button>
              <Button onClick={() => importInputRef.current?.click()}>
                {t("settings.data.importJson")}
              </Button>
              <input
                ref={importInputRef}
                type="file"
                accept=".json,application/json"
                style={{ display: "none" }}
                onChange={(e) => {
                  const file = e.target.files?.[0]
                  if (file) importJson(file)
                  if (importInputRef.current) importInputRef.current.value = ""
                }}
              />
            </Space>
            <div style={{ marginTop: "8px", fontSize: "12px", color: "var(--ss-text-secondary)" }}>
              {t("settings.data.importHint")}
            </div>
          </Card>

          <Card
            title={t("settings.data.logs")}
            style={{ backgroundColor: "var(--ss-card-bg)", color: "var(--ss-text-main)" }}
          >
            <Form layout="horizontal" labelCol={{ span: 4 }} wrapperCol={{ span: 20 }}>
              <Form.Item label={t("settings.data.logLevel")}>
                <Select
                  value={settings.log_level}
                  onChange={async (v) => {
                    if (!(window as any).api) return
                    const next = String(v) as any
                    const res = await (window as any).api.setSetting("log_level", next)
                    if (res.success) {
                      setSettings((prev) => ({ ...prev, log_level: next }))
                      messageApi.success(t("settings.general.saved"))
                    } else {
                      messageApi.error(res.message || "更新失败")
                    }
                  }}
                  style={{ width: "320px" }}
                  options={[
                    { value: "debug", label: t("settings.data.logLevels.debug") },
                    { value: "info", label: t("settings.data.logLevels.info") },
                    { value: "warn", label: t("settings.data.logLevels.warn") },
                    { value: "error", label: t("settings.data.logLevels.error") },
                  ]}
                />
              </Form.Item>
              <Form.Item label={t("settings.data.logOperation")}>
                <Space>
                  <Button loading={logsLoading} onClick={showLogs}>
                    {t("settings.data.viewLogs")}
                  </Button>
                  <Button onClick={exportLogs}>{t("settings.data.exportLogs")}</Button>
                  <Button
                    danger
                    onClick={async () => {
                      if (!(window as any).api) return
                      const res = await (window as any).api.clearLogs()
                      if (res.success) messageApi.success(t("settings.data.logsCleared"))
                      else messageApi.error(res.message || t("settings.data.clearFailed"))
                    }}
                  >
                    清空日志
                  </Button>
                </Space>
              </Form.Item>
            </Form>
          </Card>
        </>
      ),
    },
    {
      key: "url",
      label: t("settings.tabs.urlProtocol"),
      children: (
        <>
          <Card
            style={{
              backgroundColor: "var(--ss-card-bg)",
              color: "var(--ss-text-main)",
              marginBottom: "16px",
            }}
          >
            <div style={{ fontSize: "16px", fontWeight: 600, marginBottom: "8px" }}>
              {t("settings.elevation.title")}
            </div>
            <Divider />
            <div
              style={{ marginBottom: "12px", fontSize: "13px", color: "var(--ss-text-secondary)" }}
            >
              {t("settings.elevation.description")}
            </div>
            <Space style={{ marginBottom: 12 }}>
              <Tag color={elevationStatus?.is_elevated ? "success" : "warning"}>
                {elevationStatus?.is_elevated
                  ? t("settings.elevation.elevated")
                  : t("settings.elevation.notElevated")}
              </Tag>
              {elevationStatus?.platform && <Tag color="blue">{elevationStatus.platform}</Tag>}
            </Space>
            <Divider />
            <Button
              type="primary"
              loading={elevationLoading}
              disabled={
                !canAdmin || !elevationStatus?.can_request_elevation || elevationStatus?.is_elevated
              }
              onClick={handleRequestElevation}
            >
              {t("settings.elevation.request")}
            </Button>
            <div style={{ marginTop: "8px", fontSize: "12px", color: "var(--ss-text-secondary)" }}>
              {elevationStatus?.platform === "windows"
                ? t("settings.elevation.windowsHint")
                : elevationStatus?.platform === "macos"
                  ? t("settings.elevation.macosHint")
                  : t("settings.elevation.linuxHint")}
            </div>
          </Card>

          <Card style={{ backgroundColor: "var(--ss-card-bg)", color: "var(--ss-text-main)" }}>
            <div style={{ fontSize: "16px", fontWeight: 600, marginBottom: "8px" }}>
              {t("settings.url.protocol")}
            </div>
            <Divider />
            <div
              style={{ marginBottom: "12px", fontSize: "13px", color: "var(--ss-text-secondary)" }}
            >
              {t("settings.url.description")}
            </div>
            <div
              style={{
                display: "flex",
                flexDirection: "column",
                gap: "4px",
                fontSize: "12px",
                fontFamily:
                  'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", "Microsoft YaHei UI", "Microsoft YaHei", "PingFang SC", monospace',
              }}
            >
              <div>secscore://settings</div>
              <div>secscore://score</div>
            </div>
            <Divider />
            <Space style={{ marginBottom: 12 }}>
              <Tag color={urlStatus?.registered ? "success" : "error"}>
                {urlStatus?.registered
                  ? t("settings.url.statusRegistered")
                  : t("settings.url.statusNotRegistered")}
              </Tag>
              <Button size="small" loading={urlStatusLoading} onClick={loadUrlStatus}>
                {t("settings.url.checkStatus")}
              </Button>
            </Space>
            {urlStatus?.details && (
              <div
                style={{
                  marginBottom: "12px",
                  fontSize: "12px",
                  color: "var(--ss-text-secondary)",
                  wordBreak: "break-all",
                }}
              >
                {urlStatus.details}
              </div>
            )}
            <Divider />
            <Space>
              {!urlStatus?.registered ? (
                <Button
                  type="primary"
                  loading={urlRegisterLoading}
                  disabled={!canAdmin}
                  onClick={handleUrlRegister}
                >
                  {t("settings.url.register")}
                </Button>
              ) : (
                <>
                  <Button
                    loading={urlRegisterLoading}
                    disabled={!canAdmin}
                    onClick={handleUrlRegister}
                  >
                    {t("settings.url.reRegister")}
                  </Button>
                  <Button
                    danger
                    loading={urlUnregisterLoading}
                    disabled={!canAdmin}
                    onClick={handleUrlUnregister}
                  >
                    {t("settings.url.unregister")}
                  </Button>
                </>
              )}
            </Space>
            <div style={{ marginTop: "8px", fontSize: "12px", color: "var(--ss-text-secondary)" }}>
              {t("settings.url.installerRequired")}
            </div>
            {urlOperationLogs.length > 0 && (
              <>
                <Divider />
                <Collapse
                  size="small"
                  items={[
                    {
                      key: "logs",
                      label: (
                        <span style={{ fontSize: "13px" }}>
                          {t("settings.url.operationLog")} ({urlOperationLogs.length})
                        </span>
                      ),
                      children: (
                        <div
                          style={{
                            fontSize: "12px",
                            fontFamily:
                              'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
                            maxHeight: "200px",
                            overflowY: "auto",
                            lineHeight: "1.8",
                          }}
                        >
                          {urlOperationLogs.map((log, i) => (
                            <div key={i}>{log}</div>
                          ))}
                        </div>
                      ),
                    },
                  ]}
                />
              </>
            )}
          </Card>
        </>
      ),
    },
    {
      key: "about",
      label: t("settings.about.title"),
      children: (
        <Card style={{ backgroundColor: "var(--ss-card-bg)", color: "var(--ss-text-main)" }}>
          <div style={{ fontSize: "16px", fontWeight: 700, marginBottom: "8px" }}>
            {aboutContent?.title || "SecScore"}
          </div>
          <div style={{ color: "var(--ss-text-secondary)", marginBottom: "16px" }}>
            {aboutContent?.description || t("settings.about.appName")}
          </div>
          <Divider />
          <div style={{ display: "grid", gridTemplateColumns: "160px 1fr", rowGap: "10px" }}>
            <div style={{ color: "var(--ss-text-secondary)" }}>{t("settings.about.version")}</div>
            <div>{aboutContent?.version || "v1.0.0"}</div>
            <div style={{ color: "var(--ss-text-secondary)" }}>{t("settings.about.copyright")}</div>
            <div>{"CopyRight © 2025-" + currentYear + " SECTL"}</div>
            <div style={{ color: "var(--ss-text-secondary)" }}>Tauri</div>
            <div>{(window as any).electron?.process?.versions?.electron || "-"}</div>
            <div style={{ color: "var(--ss-text-secondary)" }}>Chromium</div>
            <div>{(window as any).electron?.process?.versions?.chrome || "-"}</div>
            <div style={{ color: "var(--ss-text-secondary)" }}>Node</div>
            <div>{(window as any).electron?.process?.versions?.node || "-"}</div>
            <div style={{ color: "var(--ss-text-secondary)" }}>{t("settings.about.ipcStatus")}</div>
            <div>
              <Tag color={(window as any).api ? "success" : "error"}>
                {(window as any).api
                  ? t("settings.about.ipcConnected")
                  : t("settings.about.ipcDisconnected")}
              </Tag>
            </div>
            <div style={{ color: "var(--ss-text-secondary)" }}>
              {t("settings.about.environment")}
            </div>
            <div>
              <Tag>{import.meta.env.DEV ? "Development" : "Production"}</Tag>
            </div>
          </div>
          <Divider />
          <div style={{ marginTop: "16px" }}>
            <Space>
              <Button
                onClick={() => {
                  ;(window as any).api?.toggleDevTools()
                }}
              >
                {t("settings.about.toggleDevTools")}
              </Button>
            </Space>
          </div>
          {aboutContent?.content && (
            <>
              <Divider />
              <div
                style={{
                  maxHeight: "400px",
                  overflow: "auto",
                  padding: "16px",
                  backgroundColor: "var(--ss-bg-secondary)",
                  borderRadius: "8px",
                }}
                dangerouslySetInnerHTML={{ __html: aboutContent.content }}
              />
            </>
          )}
          <Divider />
          <div style={{ fontSize: "16px", fontWeight: 600, marginBottom: "8px" }}>
            {t("settings.mcp.title")}
          </div>
          <div
            style={{ color: "var(--ss-text-secondary)", marginBottom: "12px", fontSize: "12px" }}
          >
            {t("settings.mcp.description")}
          </div>
          <Space style={{ marginBottom: "12px" }}>
            <Tag color={mcpStatus.is_running ? "success" : "default"}>
              {mcpStatus.is_running ? t("settings.mcp.running") : t("settings.mcp.stopped")}
            </Tag>
            {mcpStatus.url ? (
              <Tag color="blue">{mcpStatus.url}</Tag>
            ) : (
              <Tag>{t("settings.mcp.noUrl")}</Tag>
            )}
          </Space>
          <Form layout="horizontal" labelCol={{ span: 4 }} wrapperCol={{ span: 20 }}>
            <Form.Item label={t("settings.mcp.host")}>
              <Input
                value={mcpConfig.host}
                onChange={(e) => setMcpConfig((prev) => ({ ...prev, host: e.target.value }))}
                disabled={!canAdmin || mcpStatus.is_running}
                style={{ width: "280px" }}
                placeholder="127.0.0.1"
              />
            </Form.Item>
            <Form.Item label={t("settings.mcp.port")}>
              <Input
                value={String(mcpConfig.port)}
                onChange={(e) => {
                  const next = Number(e.target.value.replace(/[^\d]/g, ""))
                  if (Number.isFinite(next) && next > 0) {
                    setMcpConfig((prev) => ({ ...prev, port: next }))
                  } else if (!e.target.value) {
                    setMcpConfig((prev) => ({ ...prev, port: 0 }))
                  }
                }}
                disabled={!canAdmin || mcpStatus.is_running}
                style={{ width: "180px" }}
                placeholder="3901"
              />
            </Form.Item>
            <Form.Item label={t("common.operation")}>
              <Space>
                <Button
                  type="primary"
                  onClick={startMcpServer}
                  loading={mcpLoading}
                  disabled={!canAdmin || mcpStatus.is_running}
                >
                  {t("settings.mcp.start")}
                </Button>
                <Button
                  danger
                  onClick={stopMcpServer}
                  loading={mcpLoading}
                  disabled={!canAdmin || !mcpStatus.is_running}
                >
                  {t("settings.mcp.stop")}
                </Button>
                <Button onClick={loadMcpStatus} disabled={mcpLoading}>
                  {t("settings.mcp.refresh")}
                </Button>
              </Space>
            </Form.Item>
          </Form>
          <div style={{ color: "var(--ss-text-secondary)", marginTop: "-8px", fontSize: "12px" }}>
            {t("settings.mcp.hint")}
          </div>
          <Divider />
          <div style={{ fontSize: "16px", fontWeight: 600, marginBottom: "8px" }}>
            {t("settings.app.title")}
          </div>
          <div
            style={{ color: "var(--ss-text-secondary)", marginBottom: "12px", fontSize: "12px" }}
          >
            {t("settings.app.description")}
          </div>
          <div style={{ marginTop: "8px" }}>
            <Space>
              <Button onClick={confirmRestartApp} loading={appRestartLoading}>
                {t("settings.app.restart")}
              </Button>
              <Button danger onClick={confirmQuitApp} loading={appQuitLoading}>
                {t("settings.app.quit")}
              </Button>
            </Space>
          </div>
        </Card>
      ),
    },
  ]

  return (
    <div
      style={{
        padding: "24px",
        maxWidth: "900px",
        margin: "0 auto",
        color: "var(--ss-text-main)",
      }}
    >
      {contextHolder}
      <div
        style={{
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
          marginBottom: "16px",
        }}
      >
        <h2 style={{ margin: 0 }}>{t("settings.title")}</h2>
        {permissionTag}
      </div>

      <Tabs activeKey={activeTab} onChange={setActiveTab} items={tabItems} />

      <Modal
        title={recoveryDialogHeader}
        open={recoveryDialogVisible}
        onCancel={() => setRecoveryDialogVisible(false)}
        footer={
          <Button type="primary" onClick={() => setRecoveryDialogVisible(false)}>
            {t("recovery.saved")}
          </Button>
        }
        width="70%"
      >
        <div style={{ display: "flex", flexDirection: "column", gap: "12px" }}>
          <div
            style={{
              wordBreak: "break-all",
              fontFamily:
                'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", "Microsoft YaHei UI", "Microsoft YaHei", "PingFang SC", monospace',
            }}
          >
            {recoveryDialogString}
          </div>
          <Space>
            <Button
              type="primary"
              onClick={() =>
                downloadTextFile(
                  recoveryDialogFilename ||
                    `secscore_recovery_${new Date().toISOString().slice(0, 10)}.txt`,
                  `SecScore 找回字符串: ${recoveryDialogString}\n`
                )
              }
            >
              导出文本文件
            </Button>
          </Space>
          <div style={{ fontSize: "12px", color: "var(--ss-text-secondary)" }}>
            {t("recovery.exportHint")}
          </div>
        </div>
      </Modal>

      <Modal
        title={t("settings.data.systemLogs")}
        open={logsDialogVisible}
        onCancel={() => setLogsDialogVisible(false)}
        footer={<Button onClick={() => setLogsDialogVisible(false)}>{t("common.close")}</Button>}
        width="80%"
      >
        <div
          style={{
            maxHeight: "400px",
            overflowY: "auto",
            fontSize: "12px",
            fontFamily:
              'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", "Microsoft YaHei UI", "Microsoft YaHei", "PingFang SC", monospace',
            whiteSpace: "pre-wrap",
            backgroundColor: "#1e1e1e",
            color: "#d4d4d4",
            padding: "10px",
          }}
        >
          {logsText || t("settings.data.noLogs")}
        </div>
      </Modal>

      <Modal
        title={t("settings.data.confirmSettlement")}
        open={settleDialogVisible}
        onCancel={() => !settleLoading && setSettleDialogVisible(false)}
        onOk={async () => {
          if (!(window as any).api) return
          setSettleLoading(true)
          const res = await (window as any).api.createSettlement()
          setSettleLoading(false)
          if (res.success && res.data) {
            messageApi.success(t("settings.data.settlementSuccess"))
            emitDataUpdated("all")
            setSettleDialogVisible(false)
          } else {
            messageApi.error(res.message || t("settings.data.settlementFailed"))
          }
        }}
        confirmLoading={settleLoading}
        okText={t("settings.data.settle")}
      >
        <div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
          <div>{t("settings.data.settlementConfirm1")}</div>
          <div style={{ color: "var(--ss-text-secondary)", fontSize: "12px" }}>
            {t("settings.data.settlementConfirm2")}
          </div>
        </div>
      </Modal>

      <Modal
        title="确认清空所有密码？"
        open={clearDialogVisible}
        onCancel={() => !clearLoading && setClearDialogVisible(false)}
        onOk={handleConfirmClearAll}
        confirmLoading={clearLoading}
        okText="确认清空"
        okButtonProps={{ danger: true }}
      >
        清空后将关闭保护（无密码时默认视为管理权限）。
      </Modal>

      <OAuthLogin
        visible={oauthLoginVisible}
        onClose={() => setOAuthLoginVisible(false)}
        onSuccess={(userInfo) => {
          setOAuthUserInfo(userInfo)
          messageApi.success(t("settings.account.loginSuccess"))
        }}
      />
    </div>
  )
}
