import { registrationNotice } from "@dada/shared-contracts";
import { useEffect, useId, useRef, useState, type FormEvent, type KeyboardEvent } from "react";

import "./user-auth.css";

type AuthMode = "login" | "register";
type SendState = "idle" | "sending" | "sent" | "error";

interface ErrorEnvelopeBody {
  error?: {
    details?: { field_errors?: Array<{ message_key?: string }> };
    message_key?: string;
  };
}

const messageByKey: Record<string, string> = {
  "auth.account.suspended": "账号已暂停，请联系管理员。",
  "auth.challenge.expired": "验证码已过期，请重新获取。",
  "auth.challenge.invalid": "验证码不正确，请检查后重试。",
  "auth.challenge.resend_too_soon": "请等待倒计时结束后重新获取验证码。",
  "auth.challenge.too_many_attempts": "尝试次数过多，请稍后再试。",
  "auth.login.admin_required": "此邮箱需从管理员登录入口进入。",
  "auth.login.registration_required": "该邮箱尚未注册，请切换到注册。",
  "auth.email.already_registered": "该邮箱已注册，请切换到登录。",
  "auth.invite.disabled": "邀请码已停用，请更换邀请码。",
  "auth.invite.exhausted": "邀请码使用次数已耗尽，请更换邀请码。",
  "auth.invite.expired": "邀请码已过期，请更换邀请码。",
  "auth.invite.not_found": "邀请码无效，请检查后重试。",
  "auth.privacy.consent_required": "请阅读并同意《内测使用与隐私告知》。",
  "auth.privacy.notice_version_invalid": "告知版本已更新，请重新阅读后同意。",
  "auth.profile.invalid": "请检查创作署名和社交 ID。",
  "auth.registration.login_required": "该邮箱已注册，请切换到登录。",
  "auth.registration.stage_limit_reached": "本轮内测名额已满，请返回登录。",
  "auth.service.unavailable": "邮件服务暂时不可用，请稍后重试。",
};

function errorMessage(body: ErrorEnvelopeBody) {
  const key = body.error?.details?.field_errors?.[0]?.message_key ?? body.error?.message_key;
  return key ? (messageByKey[key] ?? "请求未完成，请检查后重试。") : "请求未完成，请检查后重试。";
}

function maskedEmail(email: string) {
  const [local = "", domain = ""] = email.split("@", 2);
  const visible = local.slice(0, Math.min(2, local.length));
  return `${visible}${"*".repeat(Math.max(3, local.length - visible.length))}@${domain}`;
}

function maskedRegistrationEmail(email: string) {
  const [local = "", domain = ""] = email.split("@", 2);
  return `${local.slice(0, 1)}***@${domain.slice(0, 1)}***`;
}

function maskedInvite(inviteCode: string) {
  return `••••${inviteCode.slice(-3)}`;
}

export function UserAuthPage() {
  const emailId = useId();
  const codeId = useId();
  const inviteId = useId();
  const creatorNameId = useId();
  const socialId = useId();
  const loginTab = useRef<HTMLButtonElement>(null);
  const registerTab = useRef<HTMLButtonElement>(null);
  const noticeButton = useRef<HTMLButtonElement>(null);
  const noticeCloseButton = useRef<HTMLButtonElement>(null);
  const noticeDialog = useRef<HTMLElement>(null);
  const [mode, setMode] = useState<AuthMode>("login");
  const [email, setEmail] = useState("");
  const [code, setCode] = useState("");
  const [inviteCode, setInviteCode] = useState("");
  const [creatorName, setCreatorName] = useState("");
  const [socialHandle, setSocialHandle] = useState("");
  const [privacyConsentAccepted, setPrivacyConsentAccepted] = useState(false);
  const [noticeOpen, setNoticeOpen] = useState(false);
  const [registrationId, setRegistrationId] = useState<string>();
  const [sendState, setSendState] = useState<SendState>("idle");
  const [countdown, setCountdown] = useState(0);
  const [error, setError] = useState<string>();
  const [localTestAvailable, setLocalTestAvailable] = useState(false);
  const [localTestError, setLocalTestError] = useState<string>();
  const [localTestSubmitting, setLocalTestSubmitting] = useState(false);
  const [submitting, setSubmitting] = useState(false);
  const emailValid = /^[^@\s]+@[^@\s]+$/.test(email);
  const registrationReady = Boolean(
    registrationId
    && /^[0-9]{6}$/.test(code)
    && creatorName.trim()
    && socialHandle.trim()
    && privacyConsentAccepted,
  );

  useEffect(() => {
    if (countdown <= 0) return;
    const timer = window.setInterval(() => setCountdown((value) => Math.max(0, value - 1)), 1_000);
    return () => window.clearInterval(timer);
  }, [countdown]);

  useEffect(() => {
    const controller = new AbortController();
    void fetch("/api/v1/auth/local-test", { credentials: "same-origin", signal: controller.signal })
      .then(async (response) => {
        if (!response.ok || !response.headers.get("content-type")?.includes("application/json")) return;
        const body = await response.json() as { available?: boolean };
        if (body.available === true) setLocalTestAvailable(true);
      })
      .catch(() => undefined);
    return () => controller.abort();
  }, []);

  useEffect(() => {
    if (!noticeOpen) return;
    const previousOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    noticeCloseButton.current?.focus();
    return () => {
      document.body.style.overflow = previousOverflow;
    };
  }, [noticeOpen]);

  function resetRegistrationDetails() {
    setCode("");
    setCreatorName("");
    setSocialHandle("");
    setPrivacyConsentAccepted(false);
    setNoticeOpen(false);
  }

  function switchMode(nextMode: AuthMode) {
    if (nextMode === mode) return;
    setMode(nextMode);
    resetRegistrationDetails();
    setInviteCode("");
    setRegistrationId(undefined);
    setSendState("idle");
    setCountdown(0);
    setError(undefined);
  }

  function modifyRegistrationEntry() {
    resetRegistrationDetails();
    setRegistrationId(undefined);
    setSendState("idle");
    setCountdown(0);
    setError(undefined);
    window.requestAnimationFrame(() => document.getElementById(inviteId)?.focus());
  }

  function closeNotice() {
    setNoticeOpen(false);
    window.requestAnimationFrame(() => noticeButton.current?.focus());
  }

  function handleNoticeKeyDown(event: KeyboardEvent<HTMLElement>) {
    if (event.key === "Escape") {
      event.preventDefault();
      closeNotice();
      return;
    }
    if (event.key === "Tab") {
      const focusable = Array.from(
        noticeDialog.current?.querySelectorAll<HTMLElement>("button, [href], input, [tabindex]:not([tabindex='-1'])") ?? [],
      ).filter((element) => !element.hasAttribute("disabled"));
      const first = focusable[0];
      const last = focusable.at(-1);
      if (!first || !last) return;
      if (event.shiftKey && document.activeElement === first) {
        event.preventDefault();
        last.focus();
      } else if (!event.shiftKey && document.activeElement === last) {
        event.preventDefault();
        first.focus();
      }
    }
  }

  function switchTab(nextMode: AuthMode) {
    switchMode(nextMode);
    window.requestAnimationFrame(() => (nextMode === "login" ? loginTab : registerTab).current?.focus());
  }

  async function sendCode() {
    if (!emailValid || sendState === "sending" || countdown > 0) return;
    setSendState("sending");
    setError(undefined);
    const endpoint = mode === "login" ? "/api/v1/auth/login/send" : "/api/v1/auth/register/send";
    const payload = mode === "login" ? { email } : { email, invite_code: inviteCode };
    try {
      const response = await fetch(endpoint, {
        body: JSON.stringify(payload),
        credentials: "same-origin",
        headers: { "Content-Type": "application/json" },
        method: "POST",
      });
      const body = await response.json() as ErrorEnvelopeBody & { registration_id?: string };
      if (!response.ok || !body.registration_id) {
        setSendState("error");
        setError(errorMessage(body));
        return;
      }
      setRegistrationId(body.registration_id);
      setSendState("sent");
      setCountdown(60);
    } catch {
      setSendState("error");
      setError(messageByKey["auth.service.unavailable"]);
    }
  }

  async function login(event: FormEvent) {
    event.preventDefault();
    if (!registrationId || !/^[0-9]{6}$/.test(code) || submitting) return;
    setSubmitting(true);
    setError(undefined);
    try {
      const response = await fetch("/api/v1/auth/login/complete", {
        body: JSON.stringify({ registration_id: registrationId, verification_code: code }),
        credentials: "same-origin",
        headers: {
          "Content-Type": "application/json",
          "Idempotency-Key": crypto.randomUUID().replaceAll("-", "") + crypto.randomUUID().replaceAll("-", ""),
        },
        method: "POST",
      });
      const body = await response.json() as ErrorEnvelopeBody;
      if (!response.ok) {
        setError(errorMessage(body));
        return;
      }
      window.location.assign("/app");
    } catch {
      setError("登录请求未完成，请重试。");
    } finally {
      setSubmitting(false);
    }
  }

  async function completeRegistration(event: FormEvent) {
    event.preventDefault();
    if (!registrationReady || !registrationId || submitting) return;
    setSubmitting(true);
    setError(undefined);
    try {
      const response = await fetch("/api/v1/auth/register/complete", {
        body: JSON.stringify({
          creator_name: creatorName,
          privacy_consent_accepted: privacyConsentAccepted,
          privacy_notice_version: registrationNotice.version,
          registration_id: registrationId,
          social_id: socialHandle,
          verification_code: code,
        }),
        credentials: "same-origin",
        headers: {
          "Content-Type": "application/json",
          "Idempotency-Key": crypto.randomUUID().replaceAll("-", "") + crypto.randomUUID().replaceAll("-", ""),
        },
        method: "POST",
      });
      const body = await response.json() as ErrorEnvelopeBody;
      if (!response.ok) {
        setError(errorMessage(body));
        return;
      }
      window.location.assign("/app");
    } catch {
      setError("注册请求未完成，请重试。");
    } finally {
      setSubmitting(false);
    }
  }

  async function enterLocalTest() {
    if (localTestSubmitting) return;
    setLocalTestSubmitting(true);
    setLocalTestError(undefined);
    try {
      const response = await fetch("/api/v1/auth/local-test", {
        credentials: "same-origin",
        method: "POST",
      });
      if (!response.ok) {
        setLocalTestError("本机测试会话未能建立，请重试。");
        return;
      }
      window.location.assign("/app");
    } catch {
      setLocalTestError("本机测试会话未能建立，请重试。");
    } finally {
      setLocalTestSubmitting(false);
    }
  }

  return (
    <>
      <main className="auth-page">
      <section className="auth-art" aria-label="Dada 创作艺术带">
        <div className="auth-wordmark">DADA</div>
        <div className="auth-art-copy">
          <span>LOCAL CREATIVE SYSTEM / WINDOWS P0-A</span>
          <strong>在本机展开你的创作</strong>
        </div>
        <div className="auth-art-block" aria-hidden="true" />
        <div className="auth-art-line" aria-hidden="true" />
      </section>

      <section className="auth-content">
        <a className="auth-admin-link" href="/admin/login">管理员登录</a>
        <div className="auth-panel">
          {localTestAvailable ? (
            <div className="auth-test-entry">
              <button className="auth-primary" disabled={localTestSubmitting} onClick={enterLocalTest} type="button">
                {localTestSubmitting ? "正在进入" : "直接进入本机测试"}
              </button>
              {localTestError ? <p className="auth-error" role="alert">{localTestError}</p> : null}
            </div>
          ) : null}
          <div className="auth-tabs" role="tablist" aria-label="认证方式">
            <button
              aria-selected={mode === "login"}
              className="auth-tab"
              onClick={() => switchMode("login")}
              onKeyDown={(event) => {
                if (event.key === "ArrowRight") {
                  event.preventDefault();
                  switchTab("register");
                }
              }}
              ref={loginTab}
              role="tab"
              tabIndex={mode === "login" ? 0 : -1}
              type="button"
            >
              登录
            </button>
            <button
              aria-selected={mode === "register"}
              className="auth-tab"
              onClick={() => switchMode("register")}
              onKeyDown={(event) => {
                if (event.key === "ArrowLeft") {
                  event.preventDefault();
                  switchTab("login");
                }
              }}
              ref={registerTab}
              role="tab"
              tabIndex={mode === "register" ? 0 : -1}
              type="button"
            >
              注册
            </button>
          </div>

          {mode === "login" ? (
            <form className="auth-form" onSubmit={login}>
              <h1>邮箱验证码登录</h1>
              <label htmlFor={emailId}>邮箱</label>
              <input
                autoComplete="email"
                id={emailId}
                inputMode="email"
                onChange={(event) => setEmail(event.target.value)}
                placeholder="请输入邮箱"
                type="email"
                value={email}
              />
              <label htmlFor={codeId}>验证码</label>
              <div className="auth-code-row">
                <input
                  autoComplete="one-time-code"
                  id={codeId}
                  inputMode="numeric"
                  maxLength={6}
                  onChange={(event) => setCode(event.target.value.replace(/\D/g, ""))}
                  placeholder="6 位验证码"
                  value={code}
                />
                <button
                  className="auth-secondary"
                  disabled={!emailValid || sendState === "sending" || countdown > 0}
                  onClick={sendCode}
                  type="button"
                >
                  {sendState === "sending" ? "发送中" : countdown > 0 ? `${countdown}s` : "获取验证码"}
                </button>
              </div>
              {sendState === "sent" ? (
                <p className="auth-status" role="status">验证码已发送至 {maskedEmail(email)}</p>
              ) : null}
              {error ? <p className="auth-error" role="alert">{error}</p> : null}
              <button
                className="auth-primary"
                disabled={!registrationId || code.length !== 6 || submitting}
                type="submit"
              >
                {submitting ? "登录中" : "登录"}
              </button>
            </form>
          ) : (
            <form className="auth-form auth-registration-form" onSubmit={completeRegistration}>
              <h1>{registrationId ? "完善注册资料" : "邀请码注册"}</h1>
              {!registrationId ? (
                <>
                  <label htmlFor={inviteId}>邀请码</label>
                  <input
                    autoComplete="off"
                    id={inviteId}
                    onChange={(event) => setInviteCode(event.target.value)}
                    value={inviteCode}
                  />
                  <label htmlFor={emailId}>邮箱</label>
                  <input
                    autoComplete="email"
                    id={emailId}
                    inputMode="email"
                    onChange={(event) => setEmail(event.target.value)}
                    placeholder="请输入邮箱"
                    type="email"
                    value={email}
                  />
                  <button
                    className="auth-primary"
                    disabled={!emailValid || inviteCode.trim().length < 8 || sendState === "sending" || countdown > 0}
                    onClick={sendCode}
                    type="button"
                  >
                    {sendState === "sending" ? "发送中" : countdown > 0 ? `${countdown}s` : "获取验证码"}
                  </button>
                </>
              ) : (
                <>
                  <div className="auth-registration-status">验证码已发送</div>
                  <div className="auth-verified-grid">
                    <div>
                      <strong>邀请码 · 已验证</strong>
                      <span>{maskedInvite(inviteCode)}</span>
                    </div>
                    <div>
                      <strong>邮箱 · 已验证</strong>
                      <span>{maskedRegistrationEmail(email)}</span>
                    </div>
                  </div>
                  <button className="auth-text-action" onClick={modifyRegistrationEntry} type="button">
                    修改邀请码和邮箱
                  </button>
                  <label htmlFor={codeId}>验证码</label>
                  <input
                    autoComplete="one-time-code"
                    id={codeId}
                    inputMode="numeric"
                    maxLength={6}
                    onChange={(event) => setCode(event.target.value.replace(/\D/g, ""))}
                    placeholder="输入 6 位验证码"
                    value={code}
                  />
                  <label htmlFor={creatorNameId}>创作署名</label>
                  <input
                    autoComplete="nickname"
                    id={creatorNameId}
                    maxLength={80}
                    onChange={(event) => setCreatorName(event.target.value)}
                    placeholder="成品中显示的名称"
                    value={creatorName}
                  />
                  <label htmlFor={socialId}>社交 ID</label>
                  <input
                    autoComplete="off"
                    id={socialId}
                    maxLength={80}
                    onChange={(event) => setSocialHandle(event.target.value)}
                    placeholder="成品中显示的账号文本"
                    value={socialHandle}
                  />
                  <div className="auth-consent">
                    <div className="auth-consent-title">
                      <strong>《内测使用与隐私告知》</strong>
                      <button
                        className="auth-text-action"
                        onClick={() => setNoticeOpen(true)}
                        ref={noticeButton}
                        type="button"
                      >
                        查看全文
                      </button>
                    </div>
                    <label className="auth-checkbox">
                      <input
                        checked={privacyConsentAccepted}
                        onChange={(event) => setPrivacyConsentAccepted(event.target.checked)}
                        type="checkbox"
                      />
                      我已阅读并同意《内测使用与隐私告知》
                    </label>
                    {!privacyConsentAccepted ? <p>完成注册前必须阅读并勾选同意。</p> : null}
                  </div>
                  <button className="auth-primary" disabled={!registrationReady || submitting} type="submit">
                    {submitting ? "注册中" : "注册并进入 Dada"}
                  </button>
                </>
              )}
              {error ? <p className="auth-error" role="alert">{error}</p> : null}
            </form>
          )}
        </div>
      </section>

      <footer className="auth-local-notice">
        测试数据仅保存在本机，不自动备份，也不会迁移到正式系统。
      </footer>
      </main>
      {noticeOpen ? (
        <div className="auth-dialog-backdrop">
          <section
            aria-labelledby="registration-notice-title"
            aria-modal="true"
            className="auth-dialog"
            onKeyDown={handleNoticeKeyDown}
            ref={noticeDialog}
            role="dialog"
          >
            <header>
              <div>
                <p>版本 {registrationNotice.version} · 生效日期 {registrationNotice.effectiveAt}</p>
                <h2 id="registration-notice-title">{registrationNotice.title}</h2>
              </div>
            </header>
            <div className="auth-dialog-content">
              {registrationNotice.sections.map((section) => (
                <section key={section.title}>
                  <h3>{section.title}</h3>
                  <p>{section.body}</p>
                </section>
              ))}
            </div>
            <footer>
              <button className="auth-primary" onClick={closeNotice} ref={noticeCloseButton} type="button">
                我已阅读
              </button>
            </footer>
          </section>
        </div>
      ) : null}
    </>
  );
}
