"use client"

import * as React from "react"
import { useLocale, useTranslations } from "next-intl"
import { toast } from "sonner"
import {
  ShieldCheck,
  Smartphone,
  Loader2,
  LogIn,
  LogOut,
  UserPlus,
  AlertCircle,
  LogOutIcon,
  KeyRound,
  Copy,
  Check,
  RefreshCw,
} from "lucide-react"

import {
  disableTwoFactorAction,
  getSecurityCenterAction,
  regenerateBackupCodesAction,
  revokeAllOtherSessionsAction,
  setupTwoFactorAction,
  verifyTwoFactorAction,
  type LoginHistoryItem,
  type TwoFactorSetupData,
  type TwoFactorStatus,
} from "@/modules/settings/actions-security"
import {
  formatRelativeTime,
  parseUserAgent,
} from "@/modules/settings/lib/security-utils"
import { Badge } from "@/shared/components/ui/badge"
import { Button } from "@/shared/components/ui/button"
import { Input } from "@/shared/components/ui/input"
import { Label } from "@/shared/components/ui/label"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/shared/components/ui/card"
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/shared/components/ui/dialog"

interface SecurityCenterCardProps {
  /** 当前会话的 user agent，用于标记当前会话 */
  currentDeviceLabel?: string
}

const ACTION_ICON_MAP: Record<LoginHistoryItem["action"], React.ReactNode> = {
  signin: <LogIn className="h-4 w-4" />,
  signout: <LogOut className="h-4 w-4" />,
  signup: <UserPlus className="h-4 w-4" />,
}

type SetupStep = "idle" | "qr" | "backup"

/**
 * 安全中心卡片
 *
 * 提供：
 * - 2FA TOTP 完整流程（启用 / 关闭 / 重新生成备份码）
 * - 最近登录历史（最近 10 条，来自 login_logs 表）
 * - 远程登出其他会话
 */
export function SecurityCenterCard({
  currentDeviceLabel,
}: SecurityCenterCardProps): React.ReactElement {
  const t = useTranslations("settings.security.center")
  const locale = useLocale()

  const [twoFactor, setTwoFactor] = React.useState<TwoFactorStatus | null>(null)
  const [recentLogins, setRecentLogins] = React.useState<LoginHistoryItem[]>([])
  const [loading, setLoading] = React.useState(true)
  const [revoking, setRevoking] = React.useState(false)

  // 启用 2FA Dialog 状态
  const [enableDialogOpen, setEnableDialogOpen] = React.useState(false)
  const [setupStep, setSetupStep] = React.useState<SetupStep>("idle")
  const [setupData, setSetupData] = React.useState<TwoFactorSetupData | null>(null)
  const [verifyCode, setVerifyCode] = React.useState("")
  const [backupCodes, setBackupCodes] = React.useState<string[]>([])
  const [setupLoading, setSetupLoading] = React.useState(false)
  const [copied, setCopied] = React.useState(false)

  // 关闭 2FA Dialog 状态
  const [disableDialogOpen, setDisableDialogOpen] = React.useState(false)
  const [disableCode, setDisableCode] = React.useState("")
  const [disableLoading, setDisableLoading] = React.useState(false)

  // 重新生成备份码 Dialog 状态
  const [regenDialogOpen, setRegenDialogOpen] = React.useState(false)
  const [regenCode, setRegenCode] = React.useState("")
  const [regenLoading, setRegenLoading] = React.useState(false)
  const [regenBackupCodes, setRegenBackupCodes] = React.useState<string[]>([])

  React.useEffect(() => {
    let cancelled = false
    async function load(): Promise<void> {
      try {
        const result = await getSecurityCenterAction()
        if (!cancelled && result.success && result.data) {
          setTwoFactor(result.data.twoFactor)
          setRecentLogins(result.data.recentLogins)
        }
      } catch {
        // 加载失败时静默处理
      } finally {
        if (!cancelled) setLoading(false)
      }
    }
    void load()
    return () => {
      cancelled = true
    }
  }, [])

  // --- 启用 2FA 流程 ---

  const handleEnable2FA = async (): Promise<void> => {
    setEnableDialogOpen(true)
    setSetupStep("idle")
    setSetupData(null)
    setVerifyCode("")
    setBackupCodes([])
    setSetupLoading(true)
    try {
      const result = await setupTwoFactorAction()
      if (result.success && result.data) {
        setSetupData(result.data)
        setSetupStep("qr")
      } else {
        toast.error(result.message || t("twoFactor.setupFailure"))
        setEnableDialogOpen(false)
      }
    } catch {
      toast.error(t("twoFactor.setupFailure"))
      setEnableDialogOpen(false)
    } finally {
      setSetupLoading(false)
    }
  }

  const handleVerifySetup = async (): Promise<void> => {
    if (!verifyCode.trim()) return
    setSetupLoading(true)
    try {
      const result = await verifyTwoFactorAction(verifyCode.trim())
      if (result.success && result.data) {
        setBackupCodes(result.data.backupCodes)
        setTwoFactor(result.data.status)
        setSetupStep("backup")
        toast.success(t("twoFactor.enableSuccess"))
      } else {
        toast.error(result.message || t("twoFactor.invalidCode"))
      }
    } catch {
      toast.error(t("twoFactor.verifyFailure"))
    } finally {
      setSetupLoading(false)
    }
  }

  const handleCopyBackupCodes = async (): Promise<void> => {
    try {
      await navigator.clipboard.writeText(backupCodes.join("\n"))
      setCopied(true)
      setTimeout(() => setCopied(false), 2000)
    } catch {
      // 剪贴板不可用时静默
    }
  }

  const handleCloseEnableDialog = (): void => {
    setEnableDialogOpen(false)
    setSetupStep("idle")
    setSetupData(null)
    setVerifyCode("")
    setBackupCodes([])
  }

  // --- 关闭 2FA 流程 ---

  const handleDisable2FA = async (): Promise<void> => {
    if (!disableCode.trim()) return
    setDisableLoading(true)
    try {
      const result = await disableTwoFactorAction(disableCode.trim())
      if (result.success && result.data) {
        setTwoFactor(result.data)
        setDisableDialogOpen(false)
        setDisableCode("")
        toast.success(t("twoFactor.disableSuccess"))
      } else {
        toast.error(result.message || t("twoFactor.invalidCode"))
      }
    } catch {
      toast.error(t("twoFactor.disableFailure"))
    } finally {
      setDisableLoading(false)
    }
  }

  // --- 重新生成备份码 ---

  const handleRegenerateBackupCodes = async (): Promise<void> => {
    if (!regenCode.trim()) return
    setRegenLoading(true)
    try {
      const result = await regenerateBackupCodesAction(regenCode.trim())
      if (result.success && result.data) {
        setRegenBackupCodes(result.data.backupCodes)
        setTwoFactor(result.data.status)
        setRegenCode("")
        toast.success(t("twoFactor.regenerateSuccess"))
      } else {
        toast.error(result.message || t("twoFactor.invalidCode"))
      }
    } catch {
      toast.error(t("twoFactor.regenerateFailure"))
    } finally {
      setRegenLoading(false)
    }
  }

  const handleRegenDialogOpen = (): void => {
    setRegenDialogOpen(true)
    setRegenCode("")
    setRegenBackupCodes([])
  }

  // --- 远程登出 ---

  const handleRevokeAllSessions = async (): Promise<void> => {
    setRevoking(true)
    try {
      const result = await revokeAllOtherSessionsAction()
      if (result.success && result.data) {
        if (result.data.revokedCount > 0) {
          toast.success(t("recentLogins.revokeSuccess", { count: result.data.revokedCount }))
        } else {
          toast.info(t("recentLogins.revokeSuccessEmpty"))
        }
        const refreshed = await getSecurityCenterAction()
        if (refreshed.success && refreshed.data) {
          setRecentLogins(refreshed.data.recentLogins)
        }
      } else {
        toast.error(result.message || t("recentLogins.revokeFailure"))
      }
    } catch {
      toast.error(t("recentLogins.revokeFailure"))
    } finally {
      setRevoking(false)
    }
  }

  return (
    <Card>
      <CardHeader>
        <div className="flex items-center gap-2">
          <ShieldCheck className="h-5 w-5 text-primary" />
          <div>
            <CardTitle className="text-base">{t("title")}</CardTitle>
            <CardDescription>{t("description")}</CardDescription>
          </div>
        </div>
      </CardHeader>
      <CardContent className="space-y-6">
        {/* 2FA 区域 */}
        <div className="space-y-3">
          <div className="flex items-center justify-between rounded-lg border p-4">
            <div className="flex items-start gap-3">
              <Smartphone className="mt-0.5 h-5 w-5 text-muted-foreground" />
              <div className="space-y-0.5">
                <div className="text-sm font-medium">{t("twoFactor.title")}</div>
                <p className="text-sm text-muted-foreground">
                  {t("twoFactor.description")}
                </p>
                {twoFactor?.enabled ? (
                  <div className="mt-1 flex items-center gap-2">
                    <Badge variant="secondary">{t("twoFactor.enabled")}</Badge>
                    <span className="text-xs text-muted-foreground">
                      {t("twoFactor.backupRemaining", { count: twoFactor.backupCodesRemaining })}
                    </span>
                  </div>
                ) : null}
              </div>
            </div>
            {loading ? (
              <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
            ) : twoFactor?.enabled ? (
              <Button
                type="button"
                variant="outline"
                size="sm"
                onClick={() => setDisableDialogOpen(true)}
              >
                {t("twoFactor.disable")}
              </Button>
            ) : (
              <Button
                type="button"
                size="sm"
                onClick={handleEnable2FA}
              >
                {t("twoFactor.enable")}
              </Button>
            )}
          </div>
          {twoFactor?.enabled ? (
            <div className="flex items-center justify-between rounded-lg border border-dashed p-3">
              <div className="flex items-start gap-2">
                <KeyRound className="mt-0.5 h-4 w-4 text-muted-foreground" />
                <div>
                  <div className="text-xs font-medium">{t("twoFactor.backupCodes")}</div>
                  <p className="text-xs text-muted-foreground">
                    {t("twoFactor.backupHint")}
                  </p>
                </div>
              </div>
              <Button
                type="button"
                variant="ghost"
                size="sm"
                onClick={handleRegenDialogOpen}
                className="h-7 gap-1.5 text-xs"
              >
                <RefreshCw className="h-3.5 w-3.5" />
                {t("twoFactor.regenerate")}
              </Button>
            </div>
          ) : (
            <p className="flex items-start gap-1.5 text-xs text-muted-foreground">
              <AlertCircle className="mt-0.5 h-3.5 w-3.5 flex-shrink-0" />
              {t("twoFactor.hint")}
            </p>
          )}
        </div>

        {/* 最近登录历史 */}
        <div className="space-y-3">
          <div className="flex items-center justify-between">
            <h4 className="text-sm font-medium">{t("recentLogins.title")}</h4>
            <div className="flex items-center gap-2">
              {recentLogins.length > 0 ? (
                <span className="text-xs text-muted-foreground">
                  {t("recentLogins.showingLatest", { count: recentLogins.length })}
                </span>
              ) : null}
              {!loading && recentLogins.length > 0 ? (
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  onClick={handleRevokeAllSessions}
                  disabled={revoking}
                  className="h-7 gap-1.5 text-xs"
                >
                  {revoking ? (
                    <Loader2 className="h-3.5 w-3.5 animate-spin" />
                  ) : (
                    <LogOutIcon className="h-3.5 w-3.5" />
                  )}
                  {revoking ? t("recentLogins.revoking") : t("recentLogins.revokeAll")}
                </Button>
              ) : null}
            </div>
          </div>
          {loading ? (
            <div className="flex items-center justify-center py-6">
              <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
            </div>
          ) : recentLogins.length === 0 ? (
            <div className="rounded-md border border-dashed py-6 text-center text-sm text-muted-foreground">
              {t("recentLogins.empty")}
            </div>
          ) : (
            <ul className="divide-y rounded-md border">
              {recentLogins.map((item) => {
                const { device, browser } = parseUserAgent(item.userAgent)
                const isCurrent = currentDeviceLabel
                  ? item.userAgent?.includes(currentDeviceLabel)
                  : false
                return (
                  <li
                    key={item.id}
                    className="flex items-center gap-3 px-3 py-2.5 text-sm"
                  >
                    <span
                      className={
                        item.status === "success"
                          ? "text-green-600"
                          : "text-red-600"
                      }
                    >
                      {ACTION_ICON_MAP[item.action]}
                    </span>
                    <div className="flex-1 min-w-0">
                      <div className="flex items-center gap-2">
                        <span className="font-medium">
                          {t(`recentLogins.actions.${item.action}`)}
                        </span>
                        {item.status === "failure" ? (
                          <Badge variant="destructive" className="text-xs">
                            {t("recentLogins.failed")}
                          </Badge>
                        ) : null}
                        {isCurrent ? (
                          <Badge variant="outline" className="text-xs">
                            {t("recentLogins.current")}
                          </Badge>
                        ) : null}
                      </div>
                      <div className="text-xs text-muted-foreground truncate">
                        {device} · {browser}
                        {item.ipAddress ? ` · ${item.ipAddress}` : ""}
                      </div>
                    </div>
                    <time className="text-xs text-muted-foreground whitespace-nowrap">
                      {formatRelativeTime(item.createdAt, locale)}
                    </time>
                  </li>
                )
              })}
            </ul>
          )}
        </div>
      </CardContent>

      {/* 启用 2FA Dialog */}
      <Dialog open={enableDialogOpen} onOpenChange={(o) => { if (!o) handleCloseEnableDialog() }}>
        <DialogContent className="max-w-md">
          <DialogHeader>
            <DialogTitle>{t("twoFactor.title")}</DialogTitle>
            <DialogDescription>{t("twoFactor.description")}</DialogDescription>
          </DialogHeader>

          {setupStep === "qr" && setupData ? (
            <div className="space-y-4">
              <div className="flex flex-col items-center gap-3">
                {/* eslint-disable-next-line @next/next/no-img-element */}
                <img
                  src={setupData.qrCodeDataUrl}
                  alt="2FA QR Code"
                  className="rounded-md border"
                  width={240}
                  height={240}
                />
                <p className="text-center text-sm text-muted-foreground">
                  {t("twoFactor.scanQr")}
                </p>
              </div>
              <div className="space-y-1">
                <Label className="text-xs">{t("twoFactor.manualEntry")}</Label>
                <code className="block rounded-md bg-muted p-2 text-xs break-all">
                  {setupData.secret}
                </code>
              </div>
              <div className="space-y-2">
                <Label htmlFor="verifyCode">{t("twoFactor.enterCode")}</Label>
                <Input
                  id="verifyCode"
                  type="text"
                  inputMode="numeric"
                  autoComplete="one-time-code"
                  placeholder="123456"
                  maxLength={6}
                  value={verifyCode}
                  onChange={(e) => setVerifyCode(e.target.value)}
                  disabled={setupLoading}
                  autoFocus
                />
              </div>
              <DialogFooter>
                <Button variant="outline" onClick={handleCloseEnableDialog} disabled={setupLoading}>
                  {t("twoFactor.cancel")}
                </Button>
                <Button onClick={handleVerifySetup} disabled={setupLoading || !verifyCode.trim()}>
                  {setupLoading ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : null}
                  {t("twoFactor.verify")}
                </Button>
              </DialogFooter>
            </div>
          ) : null}

          {setupStep === "backup" ? (
            <div className="space-y-4">
              <div className="rounded-md border border-amber-200 bg-amber-50 p-3 dark:border-amber-900 dark:bg-amber-950">
                <p className="flex items-start gap-1.5 text-xs text-amber-800 dark:text-amber-200">
                  <AlertCircle className="mt-0.5 h-3.5 w-3.5 flex-shrink-0" />
                  {t("twoFactor.backupWarning")}
                </p>
              </div>
              <div className="space-y-2">
                <div className="flex items-center justify-between">
                  <Label>{t("twoFactor.backupCodes")}</Label>
                  <Button
                    type="button"
                    variant="ghost"
                    size="sm"
                    onClick={handleCopyBackupCodes}
                    className="h-7 gap-1.5 text-xs"
                  >
                    {copied ? <Check className="h-3.5 w-3.5" /> : <Copy className="h-3.5 w-3.5" />}
                    {copied ? t("twoFactor.copied") : t("twoFactor.copy")}
                  </Button>
                </div>
                <div className="grid grid-cols-2 gap-2 rounded-md border p-3">
                  {backupCodes.map((code, i) => (
                    <code key={i} className="text-sm font-mono">
                      {code}
                    </code>
                  ))}
                </div>
              </div>
              <DialogFooter>
                <Button onClick={handleCloseEnableDialog}>
                  {t("twoFactor.done")}
                </Button>
              </DialogFooter>
            </div>
          ) : null}

          {setupStep === "idle" ? (
            <div className="flex items-center justify-center py-8">
              <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
            </div>
          ) : null}
        </DialogContent>
      </Dialog>

      {/* 关闭 2FA Dialog */}
      <Dialog open={disableDialogOpen} onOpenChange={setDisableDialogOpen}>
        <DialogContent className="max-w-md">
          <DialogHeader>
            <DialogTitle>{t("twoFactor.disableTitle")}</DialogTitle>
            <DialogDescription>{t("twoFactor.disableDescription")}</DialogDescription>
          </DialogHeader>
          <div className="space-y-2">
            <Label htmlFor="disableCode">{t("twoFactor.enterCodeDisable")}</Label>
            <Input
              id="disableCode"
              type="text"
              inputMode="numeric"
              autoComplete="one-time-code"
              placeholder="123456"
              maxLength={8}
              value={disableCode}
              onChange={(e) => setDisableCode(e.target.value)}
              disabled={disableLoading}
              autoFocus
            />
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setDisableDialogOpen(false)} disabled={disableLoading}>
              {t("twoFactor.cancel")}
            </Button>
            <Button
              variant="destructive"
              onClick={handleDisable2FA}
              disabled={disableLoading || !disableCode.trim()}
            >
              {disableLoading ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : null}
              {t("twoFactor.disable")}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* 重新生成备份码 Dialog */}
      <Dialog open={regenDialogOpen} onOpenChange={setRegenDialogOpen}>
        <DialogContent className="max-w-md">
          <DialogHeader>
            <DialogTitle>{t("twoFactor.regenerateTitle")}</DialogTitle>
            <DialogDescription>{t("twoFactor.regenerateDescription")}</DialogDescription>
          </DialogHeader>
          {regenBackupCodes.length === 0 ? (
            <>
              <div className="space-y-2">
                <Label htmlFor="regenCode">{t("twoFactor.enterCodeRegen")}</Label>
                <Input
                  id="regenCode"
                  type="text"
                  inputMode="numeric"
                  autoComplete="one-time-code"
                  placeholder="123456"
                  maxLength={6}
                  value={regenCode}
                  onChange={(e) => setRegenCode(e.target.value)}
                  disabled={regenLoading}
                  autoFocus
                />
              </div>
              <DialogFooter>
                <Button variant="outline" onClick={() => setRegenDialogOpen(false)} disabled={regenLoading}>
                  {t("twoFactor.cancel")}
                </Button>
                <Button
                  onClick={handleRegenerateBackupCodes}
                  disabled={regenLoading || !regenCode.trim()}
                >
                  {regenLoading ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : null}
                  {t("twoFactor.regenerate")}
                </Button>
              </DialogFooter>
            </>
          ) : (
            <div className="space-y-4">
              <div className="rounded-md border border-amber-200 bg-amber-50 p-3 dark:border-amber-900 dark:bg-amber-950">
                <p className="flex items-start gap-1.5 text-xs text-amber-800 dark:text-amber-200">
                  <AlertCircle className="mt-0.5 h-3.5 w-3.5 flex-shrink-0" />
                  {t("twoFactor.backupWarning")}
                </p>
              </div>
              <div className="grid grid-cols-2 gap-2 rounded-md border p-3">
                {regenBackupCodes.map((code, i) => (
                  <code key={i} className="text-sm font-mono">
                    {code}
                  </code>
                ))}
              </div>
              <DialogFooter>
                <Button onClick={() => setRegenDialogOpen(false)}>
                  {t("twoFactor.done")}
                </Button>
              </DialogFooter>
            </div>
          )}
        </DialogContent>
      </Dialog>
    </Card>
  )
}
