"use client";

import {
  Alert,
  Button,
  Card,
  Descriptions,
  Divider,
  Form,
  Input,
  List,
  Radio,
  Space,
  Spin,
  Tag,
  Typography,
} from "antd";
import { useEffect, useState } from "react";

const { Paragraph, Text, Title } = Typography;

type MfaStatus = {
  required: boolean;
  enrolled: boolean;
  verified: boolean;
  highRiskWritesEnabled: boolean;
  expiresIn?: number;
};

type Enrollment = {
  totpUri: string;
  backupCodes: string[];
  verificationRequired: true;
};

type Factor = "totp" | "backup";

async function mfaRequest<T>(body?: object): Promise<T> {
  const response = await fetch("/api/admin/mfa", {
    method: body ? "POST" : "GET",
    cache: "no-store",
    credentials: "same-origin",
    headers: body ? { "content-type": "application/json" } : undefined,
    body: body ? JSON.stringify(body) : undefined,
  });
  const payload = await response.json().catch(() => null) as { data?: T; error?: unknown } | null;
  if (!response.ok || !payload?.data) {
    throw new Error(typeof payload?.error === "string" ? payload.error : "MFA 请求失败，请稍后再试");
  }
  return payload.data;
}

export default function MfaSecurity() {
  const [status, setStatus] = useState<MfaStatus>();
  const [enrollment, setEnrollment] = useState<Enrollment>();
  const [backupCodes, setBackupCodes] = useState<string[]>();
  const [factor, setFactor] = useState<Factor>("totp");
  const [loading, setLoading] = useState(true);
  const [action, setAction] = useState<string>();
  const [error, setError] = useState<string>();
  const [notice, setNotice] = useState<string>();

  useEffect(() => {
    let cancelled = false;
    void mfaRequest<MfaStatus>()
      .then((value) => {
        if (!cancelled) setStatus(value);
      })
      .catch((cause: unknown) => {
        if (!cancelled) {
          setError(cause instanceof Error ? cause.message : "无法读取 MFA 状态");
        }
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, []);

  async function run<T>(name: string, operation: () => Promise<T>): Promise<T | undefined> {
    setAction(name);
    setError(undefined);
    setNotice(undefined);
    try {
      return await operation();
    } catch (cause) {
      setError(cause instanceof Error ? cause.message : "操作失败，请稍后再试");
    } finally {
      setAction(undefined);
    }
  }

  async function enroll({ password }: { password: string }) {
    const data = await run("enroll", () => mfaRequest<Enrollment>({ action: "enroll", password }));
    if (!data) return;
    setEnrollment(data);
    setBackupCodes(data.backupCodes);
    setNotice("请先保存恢复码，再使用认证器生成的 6 位验证码完成 enrollment。未验证前 MFA 不会启用。");
  }

  async function verify({ code }: { code: string }) {
    const data = await run("verify", () => mfaRequest<MfaStatus>({ action: "verify", code }));
    if (!data) return;
    setStatus(data);
    setEnrollment(undefined);
    setNotice("当前管理员 session 已完成真实第二因素验证。高风险操作仍需随后完成权限范围内的邮箱验证码。");
  }

  async function recover({ code }: { code: string }) {
    const data = await run("recover", () => mfaRequest<MfaStatus>({ action: "recover", code }));
    if (!data) return;
    setStatus(data);
    setNotice("恢复码已消费，当前 session 已完成 MFA 验证。请在恢复访问后重新生成恢复码。");
  }

  async function regenerate({ password }: { password: string }) {
    const data = await run("regenerate", () => mfaRequest<{ backupCodes: string[] }>({
      action: "regenerate",
      password,
    }));
    if (!data) return;
    setBackupCodes(data.backupCodes);
    setNotice("新的恢复码已生成，旧恢复码已全部失效。请立即离线保存。");
  }

  async function disable({ password }: { password: string }) {
    const data = await run("disable", () => mfaRequest<MfaStatus>({ action: "disable", password }));
    if (!data) return;
    setStatus(data);
    setEnrollment(undefined);
    setBackupCodes(undefined);
    setNotice(data.required
      ? "MFA 已禁用。该角色要求 MFA，因此高风险写入现已关闭，重新 enrollment 后才能恢复。"
      : "MFA 已禁用，当前 MFA 与邮箱重认证证明均已撤销。");
  }

  if (loading && !status) {
    return <Card><Space><Spin /><Text>正在读取 MFA 状态</Text></Space></Card>;
  }

  return <Space direction="vertical" size="large" style={{ width: "100%" }}>
    <div>
      <Title level={2}>安全验证</Title>
      <Paragraph type="secondary">
        管理员 MFA 使用 Better Auth 的真实 TOTP 与一次性恢复码。MFA 证明只绑定当前 server session，短时有效且可随 session 撤销。
      </Paragraph>
    </div>

    {error ? <Alert type="error" showIcon message={error} /> : null}
    {notice ? <Alert type="success" showIcon message={notice} /> : null}
    {status?.required && !status.enrolled ? <Alert
      type="warning"
      showIcon
      message="当前角色强制要求 MFA"
      description="在 enrollment 完成前，所有高风险写入都会 fail closed。"
    /> : null}

    <Card title="当前状态">
      <Descriptions column={{ xs: 1, sm: 2 }}>
        <Descriptions.Item label="角色要求">
          <Tag color={status?.required ? "red" : "default"}>{status?.required ? "必须 MFA" : "可选 MFA"}</Tag>
        </Descriptions.Item>
        <Descriptions.Item label="Enrollment">
          <Tag color={status?.enrolled ? "green" : "orange"}>{status?.enrolled ? "已启用" : "未启用"}</Tag>
        </Descriptions.Item>
        <Descriptions.Item label="当前 session">
          <Tag color={status?.verified ? "green" : "default"}>{status?.verified ? "已验证" : "未验证"}</Tag>
        </Descriptions.Item>
        <Descriptions.Item label="高风险写入前置能力">
          <Tag color={status?.highRiskWritesEnabled ? "green" : "red"}>
            {status?.highRiskWritesEnabled ? "可发起邮箱重认证" : "已关闭"}
          </Tag>
        </Descriptions.Item>
      </Descriptions>
    </Card>

    {!status?.enrolled && !enrollment ? <Card title="启用 TOTP MFA">
      <Paragraph>输入当前账户密码后生成认证器 URI 与一次性恢复码。服务器只保存加密后的 seed 与恢复码。</Paragraph>
      <Form layout="vertical" onFinish={enroll} style={{ maxWidth: 520 }}>
        <Form.Item name="password" label="当前密码" rules={[{ required: true, message: "请输入当前密码" }]}>
          <Input.Password autoComplete="current-password" maxLength={128} />
        </Form.Item>
        <Button type="primary" htmlType="submit" loading={action === "enroll"}>开始 enrollment</Button>
      </Form>
    </Card> : null}

    {enrollment ? <Card title="完成 enrollment">
      <Alert
        type="info"
        showIcon
        message="先保存恢复码，再验证 TOTP"
        description="刷新页面不会再次显示这些明文恢复码。不要把 URI、seed 或恢复码粘贴到日志、工单或聊天中。"
      />
      <Divider orientation="left">认证器 URI</Divider>
      <Paragraph copyable={{ text: enrollment.totpUri }} code style={{ overflowWrap: "anywhere" }}>
        {enrollment.totpUri}
      </Paragraph>
      <Divider orientation="left">一次性恢复码</Divider>
      <BackupCodeList codes={backupCodes ?? enrollment.backupCodes} />
      <Divider />
      <Form layout="vertical" onFinish={verify} style={{ maxWidth: 520 }}>
        <Form.Item name="code" label="认证器验证码" rules={[{ required: true }, { pattern: /^\d{6}$/, message: "请输入 6 位验证码" }]}>
          <Input inputMode="numeric" autoComplete="one-time-code" maxLength={6} />
        </Form.Item>
        <Button type="primary" htmlType="submit" loading={action === "verify"}>验证并启用 MFA</Button>
      </Form>
    </Card> : null}

    {status?.enrolled && !status.verified ? <Card title="验证当前 session">
      <Paragraph>高权限操作前，先用认证器验证码或一次性恢复码完成真实第二因素。</Paragraph>
      <Radio.Group value={factor} onChange={(event) => setFactor(event.target.value as Factor)}>
        <Radio.Button value="totp">认证器验证码</Radio.Button>
        <Radio.Button value="backup">恢复码</Radio.Button>
      </Radio.Group>
      <Form
        key={factor}
        layout="vertical"
        onFinish={factor === "totp" ? verify : recover}
        style={{ maxWidth: 520, marginTop: 16 }}
      >
        <Form.Item
          name="code"
          label={factor === "totp" ? "6 位验证码" : "一次性恢复码"}
          rules={factor === "totp"
            ? [{ required: true }, { pattern: /^\d{6}$/, message: "请输入 6 位验证码" }]
            : [{ required: true, whitespace: true }]}
        >
          <Input
            inputMode={factor === "totp" ? "numeric" : "text"}
            autoComplete="one-time-code"
            maxLength={factor === "totp" ? 6 : 128}
          />
        </Form.Item>
        <Button type="primary" htmlType="submit" loading={action === "verify" || action === "recover"}>
          验证当前 session
        </Button>
      </Form>
    </Card> : null}

    {status?.enrolled && status.verified ? <Card title="恢复与禁用">
      <Space direction="vertical" size="large" style={{ width: "100%" }}>
        <div>
          <Title level={4}>重新生成恢复码</Title>
          <Paragraph type="secondary">生成后旧恢复码立即失效，明文只在本次响应显示。</Paragraph>
          <Form layout="inline" onFinish={regenerate}>
            <Form.Item name="password" rules={[{ required: true, message: "请输入当前密码" }]}>
              <Input.Password placeholder="当前密码" autoComplete="current-password" maxLength={128} />
            </Form.Item>
            <Button htmlType="submit" loading={action === "regenerate"}>重新生成</Button>
          </Form>
        </div>
        {backupCodes?.length ? <BackupCodeList codes={backupCodes} /> : null}
        <Divider />
        <div>
          <Title level={4}>禁用 MFA</Title>
          <Paragraph type="secondary">禁用会轮换 Better Auth session，并撤销当前 MFA 与邮箱重认证证明。</Paragraph>
          <Form layout="inline" onFinish={disable}>
            <Form.Item name="password" rules={[{ required: true, message: "请输入当前密码" }]}>
              <Input.Password placeholder="当前密码" autoComplete="current-password" maxLength={128} />
            </Form.Item>
            <Button danger htmlType="submit" loading={action === "disable"}>禁用 MFA</Button>
          </Form>
        </div>
      </Space>
    </Card> : null}
  </Space>;
}

function BackupCodeList({ codes }: { codes: string[] }) {
  return <List
    bordered
    size="small"
    dataSource={codes}
    grid={{ gutter: 8, xs: 1, sm: 2, md: 3 }}
    renderItem={(code) => <List.Item><Text code>{code}</Text></List.Item>}
  />;
}
