import { type FormEvent, useEffect, useId, useState } from "react";

import "./account-settings.css";

interface SettingsPayload {
  account: { email: string; status: "active" };
  csrf_token: string;
  local_data: {
    backup_enabled: false;
    capacity_status: "normal" | "warning" | "critical" | "full" | "unavailable";
    hard_limit_bytes: number;
    location: "configured_local_data_root";
    managed_content_bytes: number;
    migration_supported: false;
  };
  profile: { creator_name: string; social_id: string };
}

function formatBytes(bytes: number) {
  if (bytes >= 1024 ** 3) return `${(bytes / 1024 ** 3).toFixed(2)} GB`;
  if (bytes >= 1024 ** 2) return `${(bytes / 1024 ** 2).toFixed(1)} MB`;
  return `${Math.max(0, bytes)} B`;
}

function capacityLabel(status: SettingsPayload["local_data"]["capacity_status"]) {
  if (status === "full") return "本机容量已满";
  if (status === "unavailable") return "本机数据暂不可写";
  if (status === "critical") return "本机容量接近上限";
  if (status === "warning") return "本机容量需要关注";
  return "本机容量正常";
}

export function AccountSettingsPage() {
  const creatorNameId = useId();
  const socialId = useId();
  const confirmationId = useId();
  const deletionCodeId = useId();
  const [settings, setSettings] = useState<SettingsPayload>();
  const [creatorName, setCreatorName] = useState("");
  const [socialHandle, setSocialHandle] = useState("");
  const [loadingError, setLoadingError] = useState(false);
  const [saving, setSaving] = useState(false);
  const [saveError, setSaveError] = useState(false);
  const [saved, setSaved] = useState(false);
  const [deletionOpen, setDeletionOpen] = useState(false);
  const [deletionId, setDeletionId] = useState<string>();
  const [deletionCode, setDeletionCode] = useState("");
  const [confirmation, setConfirmation] = useState("");
  const [sendingCode, setSendingCode] = useState(false);
  const [deleting, setDeleting] = useState(false);
  const [deletionError, setDeletionError] = useState(false);

  useEffect(() => {
    let active = true;
    void fetch("/api/v1/account/settings", { credentials: "same-origin" })
      .then(async (response) => {
        if (!response.ok) throw new Error("settings_load_failed");
        return response.json() as Promise<SettingsPayload>;
      })
      .then((payload) => {
        if (!active) return;
        setSettings(payload);
        setCreatorName(payload.profile.creator_name);
        setSocialHandle(payload.profile.social_id);
      })
      .catch(() => {
        if (active) setLoadingError(true);
      });
    return () => { active = false; };
  }, []);

  async function saveProfile(event: FormEvent) {
    event.preventDefault();
    if (!settings || saving || !creatorName.trim() || !socialHandle.trim()) return;
    setSaving(true);
    setSaveError(false);
    setSaved(false);
    try {
      const response = await fetch("/api/v1/account/settings/profile", {
        body: JSON.stringify({ creator_name: creatorName, social_id: socialHandle }),
        credentials: "same-origin",
        headers: { "Content-Type": "application/json", "X-CSRF-Token": settings.csrf_token },
        method: "PUT",
      });
      if (!response.ok) throw new Error("profile_save_failed");
      setSaved(true);
    } catch {
      setSaveError(true);
    } finally {
      setSaving(false);
    }
  }

  async function sendDeletionCode() {
    if (!settings || sendingCode || deleting) return;
    setSendingCode(true);
    setDeletionError(false);
    try {
      const response = await fetch("/api/v1/account/deletion/send", {
        credentials: "same-origin",
        headers: { "X-CSRF-Token": settings.csrf_token },
        method: "POST",
      });
      const body = await response.json() as { deletion_id?: string };
      if (!response.ok || !body.deletion_id) throw new Error("deletion_code_failed");
      setDeletionId(body.deletion_id);
    } catch {
      setDeletionError(true);
    } finally {
      setSendingCode(false);
    }
  }

  async function completeDeletion(event: FormEvent) {
    event.preventDefault();
    if (!settings || !deletionId || deletionCode.length !== 6 || confirmation !== "注销账号" || deleting) return;
    setDeleting(true);
    setDeletionError(false);
    try {
      const response = await fetch("/api/v1/account/deletion/complete", {
        body: JSON.stringify({ confirmation, deletion_id: deletionId, verification_code: deletionCode }),
        credentials: "same-origin",
        headers: {
          "Content-Type": "application/json",
          "Idempotency-Key": crypto.randomUUID().replaceAll("-", "") + crypto.randomUUID().replaceAll("-", ""),
          "X-CSRF-Token": settings.csrf_token,
        },
        method: "POST",
      });
      if (!response.ok) throw new Error("account_deletion_failed");
      window.location.assign("/");
    } catch {
      setDeletionError(true);
      setDeleting(false);
    }
  }

  function closeDeletion() {
    if (deleting) return;
    setDeletionOpen(false);
    setDeletionId(undefined);
    setDeletionCode("");
    setConfirmation("");
    setDeletionError(false);
  }

  if (!settings && !loadingError) {
    return <main className="settings-loading" aria-live="polite">正在读取设置</main>;
  }

  if (!settings) {
    return (
      <main className="settings-loading">
        <p role="alert">设置暂时无法读取。</p>
        <button onClick={() => window.location.reload()} type="button">重新读取</button>
      </main>
    );
  }

  const capacityPercent = Math.min(100, Math.round((settings.local_data.managed_content_bytes / settings.local_data.hard_limit_bytes) * 100));

  return (
    <main className="settings-page">
      <header className="settings-header">
        <a className="settings-brand" href="/app">DADA</a>
        <nav aria-label="账号导航">
          <a href="/app">创作工作台</a>
          <span aria-current="page">设置</span>
        </nav>
      </header>

      <div className="settings-title">
        <p>ACCOUNT / LOCAL DATA</p>
        <h1>设置与本机数据</h1>
      </div>

      <section className="settings-section" aria-labelledby="profile-title">
        <div className="settings-section-heading">
          <h2 id="profile-title">个人资料</h2>
          <p>用于生成内容中的署名信息。</p>
        </div>
        <form className="settings-form" onSubmit={saveProfile}>
          <label htmlFor={creatorNameId}>创作署名</label>
          <input id={creatorNameId} maxLength={80} onChange={(event) => setCreatorName(event.target.value)} value={creatorName} />
          <label htmlFor={socialId}>社交 ID</label>
          <input id={socialId} maxLength={80} onChange={(event) => setSocialHandle(event.target.value)} value={socialHandle} />
          {saveError ? <p className="settings-error" role="alert">保存失败，当前输入已保留，请重试。</p> : null}
          {saved ? <p className="settings-saved" role="status">资料已保存。</p> : null}
          <button className="settings-primary" disabled={saving || !creatorName.trim() || !socialHandle.trim()} type="submit">
            {saving ? "保存中" : "保存资料"}
          </button>
        </form>
      </section>

      <section className="settings-section" aria-labelledby="account-title">
        <div className="settings-section-heading">
          <h2 id="account-title">账号</h2>
          <p>邮箱仅用于验证码认证。</p>
        </div>
        <dl className="settings-definition">
          <div><dt>邮箱</dt><dd>{settings.account.email}</dd></div>
          <div><dt>状态</dt><dd>正常</dd></div>
          <div><dt>登录方式</dt><dd>邮箱验证码</dd></div>
        </dl>
      </section>

      <section className="settings-section settings-local" aria-labelledby="local-title">
        <div className="settings-section-heading">
          <h2 id="local-title">本机数据</h2>
          <p>逻辑位置：Dada 配置的本机数据目录</p>
        </div>
        <div className="settings-capacity" data-status={settings.local_data.capacity_status}>
          <div>
            <strong>{capacityLabel(settings.local_data.capacity_status)}</strong>
            <span>{formatBytes(settings.local_data.managed_content_bytes)} / {formatBytes(settings.local_data.hard_limit_bytes)}</span>
          </div>
          <div className="settings-capacity-track" role="progressbar" aria-label="本机数据容量" aria-valuemax={100} aria-valuemin={0} aria-valuenow={capacityPercent}>
            <span style={{ width: `${capacityPercent}%` }} />
          </div>
        </div>
        <p className="settings-fixed-notice">测试数据仅保存在本机，不自动备份，也不会迁移到正式系统。</p>
        <p className="settings-detail">数据依赖当前 Windows 用户登录和文件系统权限，不提供 Dada 应用层加密或云备份。机器损坏、重装或删除本机数据目录后无法恢复。</p>
      </section>

      <section className="settings-danger" aria-labelledby="danger-title">
        <div>
          <h2 id="danger-title">注销账号</h2>
          <p>注销会立即删除账号资料、未使用点数和全部作品，并使所有会话失效。</p>
        </div>
        <button className="settings-danger-button" onClick={() => setDeletionOpen(true)} type="button">注销账号</button>
      </section>

      {deletionOpen ? (
        <div className="settings-dialog-backdrop">
          <section
            aria-labelledby="delete-dialog-title"
            aria-modal="true"
            className="settings-dialog"
            onKeyDown={(event) => {
              if (event.key === "Escape" && !deleting) closeDeletion();
            }}
            role="dialog"
          >
            <header>
              <div>
                <p>DANGER ZONE</p>
                <h2 id="delete-dialog-title">确认注销账号</h2>
              </div>
              <button aria-label="关闭注销确认" autoFocus disabled={deleting} onClick={closeDeletion} type="button">×</button>
            </header>
            <div className="settings-dialog-body">
              <p className="settings-dialog-warning">账号、资料、项目、图片、坐标、成品和未使用点数将立即删除且不可恢复。</p>
              <p>匿名生成与点数事件最多保留 180 天，只保留随机主体、时间、模型、结果、错误类别和点数变化；不会保留邮箱或作品内容。</p>
              <button className="settings-code-button" disabled={sendingCode || deleting || Boolean(deletionId)} onClick={sendDeletionCode} type="button">
                {sendingCode ? "发送中" : deletionId ? "验证码已发送" : "获取注销验证码"}
              </button>
              <form onSubmit={completeDeletion}>
                <label htmlFor={deletionCodeId}>注销验证码</label>
                <input disabled={deleting || !deletionId} id={deletionCodeId} inputMode="numeric" maxLength={6} onChange={(event) => setDeletionCode(event.target.value.replace(/\D/g, ""))} value={deletionCode} />
                <label htmlFor={confirmationId}>确认词</label>
                <input disabled={deleting} id={confirmationId} onChange={(event) => setConfirmation(event.target.value)} placeholder="输入：注销账号" value={confirmation} />
                {deletionError ? <p className="settings-error" role="alert">注销请求未完成，请核对验证码后重试。</p> : null}
                <button className="settings-delete-confirm" disabled={!deletionId || deletionCode.length !== 6 || confirmation !== "注销账号" || deleting} type="submit">
                  {deleting ? "注销处理中" : "永久注销"}
                </button>
              </form>
            </div>
          </section>
        </div>
      ) : null}
    </main>
  );
}
