"use client";

import { useEffect, useRef, useState } from "react";
import { PairingCancelButton } from "../PairingCancelButton";
import {
  buildDaemonRegistrationCommand,
  daemonStartCommand,
  type SupportedHostOS,
} from "./onboarding";
import type { PairingAccessState } from "../../onboarding";

type PairingResult = { id: string; bootstrapToken: string; expiresAt: string };
type PairingView = PairingResult & {
  requestedName: string;
  os: SupportedHostOS;
};
type PairingProgress = {
  id: string;
  status: "waiting" | "claimed" | "expired" | "locked" | "cancelled";
  expiresAt: string;
  claimedHostId: string | null;
  claimedAt: string | null;
  claimAttemptState: "not_seen" | "seen" | "invalid";
  lastClaimAttemptAt: string | null;
};
type PairingTerminal = Exclude<PairingProgress["status"], "waiting" | "claimed">;
type PairingCompletion = {
  hostId: string;
  claimedAt: string;
};
type CopyTarget = "command" | "token" | "start";
const unavailableCopy: Record<Exclude<PairingAccessState, "available">, { title: string; detail: string; href: string; action: string; readiness?: boolean }> = {
  request_pending: {
    title: "免费闭测申请正在审核",
    detail: "处理结果会显示在公测权益页；审核期间不需要重复申请。",
    href: "/dashboard/billing",
    action: "查看申请进度",
  },
  gated: {
    title: "公开接入仍由安全门禁阻止",
    detail: "免费政策已经预设，但 P0 证据尚未齐全。可以申请小范围免费闭测资格。",
    href: "/dashboard/billing",
    action: "申请免费闭测",
    readiness: true,
  },
  inactive: {
    title: "公开公测当前未开放",
    detail: "该账户没有有效的免费公测或闭测邀请；可以提交闭测申请，不会因此创建订单或要求付款。",
    href: "/dashboard/billing",
    action: "申请免费闭测",
  },
  full: {
    title: "当前没有可用主机槽位",
    detail: "已有主机和等待中的配对请求已经占满当前免费容量，请先取消旧请求或联系管理员调整邀请。",
    href: "/dashboard/hosts",
    action: "管理主机和配对",
  },
};
const terminalCopy: Record<PairingTerminal, { title: string; detail: string }> = {
  expired: {
    title: "这枚配对码已经过期",
    detail: "十分钟有效期已经结束，原码不能恢复。确认 daemon 已准备好后再生成一枚新码。",
  },
  locked: {
    title: "这枚配对码已经锁定",
    detail: "错误尝试次数已达到上限，原码不能继续使用。请核对 daemon 和复制步骤后重新生成。",
  },
  cancelled: {
    title: "这枚配对码已经取消",
    detail: "原码已失效并释放预留容量；需要接入时可以重新生成。",
  },
};

export function PairingForm({
  accessState,
  releaseAvailable,
  minimumDaemonVersion,
  connectOrigin,
}: {
  accessState: PairingAccessState;
  releaseAvailable: boolean;
  minimumDaemonVersion: string;
  connectOrigin: string;
}) {
  const [name, setName] = useState("");
  const [os, setOs] = useState<SupportedHostOS>("windows");
  const [pairing, setPairing] = useState<PairingView | null>(null);
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);
  const [copied, setCopied] = useState<CopyTarget | null>(null);
  const [copyError, setCopyError] = useState("");
  const [closedBetaBuildConfirmed, setClosedBetaBuildConfirmed] = useState(false);
  const [progressError, setProgressError] = useState("");
  const [completion, setCompletion] = useState<PairingCompletion | null>(null);
  const [terminal, setTerminal] = useState<PairingTerminal | null>(null);
  const [claimAttempt, setClaimAttempt] = useState<Pick<
    PairingProgress,
    "claimAttemptState" | "lastClaimAttemptAt"
  >>({ claimAttemptState: "not_seen", lastClaimAttemptAt: null });
  const resultHeading = useRef<HTMLHeadingElement>(null);
  const pairingId = pairing?.id ?? null;

  useEffect(() => {
    if (pairing) resultHeading.current?.focus();
  }, [pairing]);

  useEffect(() => {
    if (!pairingId) return;
    let active = true;
    let timer: number | undefined;

    async function poll() {
      try {
        const response = await fetch(
          `/api/hosts/pairing?pairing_id=${encodeURIComponent(pairingId!)}`,
          { cache: "no-store" },
        );
        const body = (await response.json()) as {
          pairing?: PairingProgress;
          message?: string;
        };
        if (!active) return;
        if (!response.ok || !body.pairing) {
          throw new Error(body.message || "暂时无法确认配对状态");
        }
        setProgressError("");
        setClaimAttempt({
          claimAttemptState: body.pairing.claimAttemptState,
          lastClaimAttemptAt: body.pairing.lastClaimAttemptAt,
        });
        if (body.pairing.status === "claimed" && body.pairing.claimedHostId && body.pairing.claimedAt) {
          setCompletion({
            hostId: body.pairing.claimedHostId,
            claimedAt: body.pairing.claimedAt,
          });
          setPairing(null);
          setCopied(null);
          setCopyError("");
          return;
        }
        if (
          body.pairing.status === "expired"
          || body.pairing.status === "locked"
          || body.pairing.status === "cancelled"
        ) {
          setTerminal(body.pairing.status);
          setPairing(null);
          setCopied(null);
          setCopyError("");
          return;
        }
        timer = window.setTimeout(poll, 2_000);
      } catch (pollError) {
        if (!active) return;
        setProgressError(
          pollError instanceof Error
            ? `${pollError.message}；页面会继续重试。`
            : "暂时无法确认配对状态；页面会继续重试。",
        );
        timer = window.setTimeout(poll, 5_000);
      }
    }

    timer = window.setTimeout(poll, 1_000);
    return () => {
      active = false;
      if (timer !== undefined) window.clearTimeout(timer);
    };
  }, [pairingId]);

  if (accessState !== "available") {
    const copy = unavailableCopy[accessState];
    return (
      <div className="empty-state pairing-access-blocked" role="status">
        <span className="empty-symbol">×</span>
        <h2>{copy.title}</h2>
        <p>{copy.detail}</p>
        <div className="pairing-result-actions">
          <a className="button button-primary" href={copy.href}>{copy.action}</a>
          {copy.readiness && <a className="button button-secondary" href="/readiness">查看公测门禁</a>}
          <a className="button button-secondary" href="/dashboard">返回总览</a>
        </div>
      </div>
    );
  }

  async function copyText(value: string, target: CopyTarget) {
    setCopyError("");
    try {
      if (!navigator.clipboard?.writeText) throw new Error("clipboard_unavailable");
      await navigator.clipboard.writeText(value);
      setCopied(target);
    } catch {
      setCopied(null);
      setCopyError("浏览器未允许自动复制。请点入对应文本框，使用 Ctrl+C 或系统复制操作手动复制。");
    }
  }

  async function submit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setError("");
    setTerminal(null);
    setCompletion(null);
    if (!releaseAvailable && !closedBetaBuildConfirmed) {
      setError("公开下载尚未就绪。请先取得并核验兼容的闭测构建，再确认后生成配对码。");
      return;
    }
    setLoading(true);
    try {
      const response = await fetch("/api/hosts/pairing", {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({ requestedName: name, os }),
      });
      const body = (await response.json()) as { pairing?: PairingResult; message?: string };
      if (!response.ok || !body.pairing) throw new Error(body.message || "无法创建配对请求");
      setPairing({
        ...body.pairing,
        requestedName: name.trim(),
        os,
      });
      setCopied(null);
      setCopyError("");
      setProgressError("");
      setClaimAttempt({ claimAttemptState: "not_seen", lastClaimAttemptAt: null });
    } catch (submitError) {
      setError(submitError instanceof Error ? submitError.message : "无法创建配对请求");
    } finally {
      setLoading(false);
    }
  }

  if (completion) {
    return (
      <div className="empty-state pairing-complete" role="status">
        <span className="empty-symbol">✓</span>
        <h2>主机已成功认领</h2>
        <p>一次性配对码已经从页面状态中清除。控制平面已建立可撤销设备凭据并推进授权 revision；daemon 会继续连接同一个服务地址。</p>
        <small>认领时间：{new Date(completion.claimedAt).toLocaleString("zh-CN")} · 主机编号 {completion.hostId}</small>
        <div className="pairing-result-actions">
          <a className="button button-primary" href="/dashboard/hosts">查看主机与开通状态</a>
          <button className="button button-secondary" type="button" onClick={() => setCompletion(null)}>再添加一台主机</button>
        </div>
      </div>
    );
  }

  if (terminal) {
    const copy = terminalCopy[terminal];
    return (
      <div className="empty-state pairing-terminal" role="status">
        <span className="empty-symbol">×</span>
        <h2>{copy.title}</h2>
        <p>{copy.detail}</p>
        <div className="pairing-result-actions">
          <button className="button button-primary" type="button" onClick={() => setTerminal(null)}>重新生成配对码</button>
          <a className="button button-secondary" href="/dashboard/hosts">查看主机和配对</a>
        </div>
      </div>
    );
  }

  if (pairing) {
    const registrationCommand = buildDaemonRegistrationCommand({
      os: pairing.os,
      connectOrigin,
      hostName: pairing.requestedName,
    });
    const startCommand = daemonStartCommand(pairing.os);
    return (
      <div className="pairing-result">
        <span className="eyebrow">PAIRING REQUEST CREATED</span>
        <h2 ref={resultHeading} tabIndex={-1}>在 {pairing.os === "windows" ? "Windows" : "Linux"} 主机完成注册</h2>
        <p>命令已按 Cloud 稳定 Connect 服务地址和主机名生成。一次性码不会拼进命令、URL 或浏览器存储。</p>
        <div className="pairing-progress" role="status" aria-live="polite">
          <strong>{claimAttempt.claimAttemptState === "seen" ? "Cloud 已收到请求，但尚未认领" : claimAttempt.claimAttemptState === "invalid" ? "认领尝试时间待核实" : "尚未收到注册请求"}</strong>
          <span>{claimAttempt.claimAttemptState === "seen"
            ? `最近一次尝试：${new Date(claimAttempt.lastClaimAttemptAt!).toLocaleString("zh-CN")}。这只证明 Cloud 收到过针对该配对 ID 的请求，不证明来源一定是你的 daemon。请先查看终端错误，并核对系统类型、配对码、daemon 版本和 identity.json；当前码有效时无需反复生成。`
            : claimAttempt.claimAttemptState === "invalid"
              ? "Cloud 找到过针对这枚配对请求的记录，但时间异常，不能判断先后；请查看终端错误或提交反馈。"
              : "请先在目标主机运行注册命令并粘贴一次性码。页面每两秒确认一次，尚未收到请求通常表示命令未运行、地址不可达或请求还没发出。"}</span>
        </div>
        {progressError && <p className="form-error" role="alert">{progressError}</p>}
        <a className="text-link pairing-download-link" href="/download">还没有兼容 daemon？先查看下载与 SHA-256 校验 →</a>

        <ol className="registration-steps">
          <li>
            <strong>复制命令，在 daemon 所在目录运行</strong>
            <label className="pairing-copy-field">
              <span>{pairing.os === "windows" ? "PowerShell" : "Bash"} 注册命令</span>
              <textarea
                readOnly
                rows={pairing.os === "windows" ? 12 : 10}
                value={registrationCommand}
                onFocus={(event) => event.currentTarget.select()}
                aria-describedby="registration-command-note"
              />
            </label>
            <button className="button button-secondary" type="button" onClick={() => copyText(registrationCommand, "command")}>{copied === "command" ? "命令已复制" : "复制注册命令"}</button>
            <small id="registration-command-note">运行后终端会隐藏输入并等待你粘贴一次性码。</small>
          </li>
          <li>
            <strong>终端出现提示后，再复制并粘贴一次性码</strong>
            <label className="pairing-copy-field">
              <span>一次性配对码</span>
              <input readOnly value={pairing.bootstrapToken} onFocus={(event) => event.currentTarget.select()} autoComplete="off" spellCheck={false} />
            </label>
            <button className="button button-secondary" type="button" onClick={() => copyText(pairing.bootstrapToken, "token")}>{copied === "token" ? "配对码已复制" : "复制一次性配对码"}</button>
            <small>有效期至 {new Date(pairing.expiresAt).toLocaleString("zh-CN")}；终端输入不会回显。</small>
          </li>
          <li>
            <strong>注册成功后启动 daemon</strong>
            <label className="pairing-copy-field compact">
              <span>启动命令</span>
              <input readOnly value={startCommand} onFocus={(event) => event.currentTarget.select()} />
            </label>
            <button className="button button-secondary" type="button" onClick={() => copyText(startCommand, "start")}>{copied === "start" ? "启动命令已复制" : "复制启动命令"}</button>
            <small>保持 daemon 运行；控制面认领完成后，它会在同一个稳定服务地址等待共享 Relay 就绪，不需要轮询或切换后端地址。</small>
          </li>
        </ol>

        {copyError && <p className="form-error" role="alert">{copyError}</p>}
        {copied && !copyError && <p className="form-success" role="status">复制成功。配对码使用后请用普通文本覆盖剪贴板。</p>}
        <div className="prototype-callout"><strong>使用后立即清除</strong><span>注册命令会在结束时清除进程环境中的配对码；认领成功后服务端摘要也会立即失效。如果响应中途丢失，请在主机列表撤销记录后重新配对。不要截图或写入日志。</span></div>
        <div className="prototype-callout"><strong>恢复原记录需要最新版 daemon</strong><span>保留 identity.json、删除旧 config.json 后重新注册。恢复请求会用原 Ed25519 私钥签名；旧版 daemon 或只有公开指纹的请求会被拒绝。</span></div>
        <div className="prototype-callout"><strong>当前接入边界</strong><span>控制平面会签发独立、可撤销的设备令牌；席位只决定主机能否加入租户，不会自动授予手机读取这台主机的权限。</span></div>
        <div className="pairing-result-actions">
          <a className="button button-secondary" href="/dashboard/hosts">返回主机列表</a>
          <PairingCancelButton
            pairingId={pairing.id}
            onCancelled={() => {
              setPairing(null);
              setTerminal("cancelled");
              setCopied(null);
              setCopyError("");
              setProgressError("");
            }}
          />
        </div>
      </div>
    );
  }

  return (
    <form className="cloud-form pairing-form" onSubmit={submit}>
      {!releaseAvailable && (
        <div className="prototype-callout daemon-preflight" role="group" aria-labelledby="daemon-preflight-title">
          <strong id="daemon-preflight-title">公开 daemon 下载尚未就绪</strong>
          <span>当前不会把你送去下载不确定的“最新版”。只有已经从管理员处取得兼容构建，并核对版本与 SHA-256 的闭测参与者，才应生成十分钟配对码。</span>
          <a className="text-link" href="/download">查看最低 v{minimumDaemonVersion} 要求与下载状态 →</a>
          <label className="switch-row">
            <input type="checkbox" checked={closedBetaBuildConfirmed} onChange={(event) => setClosedBetaBuildConfirmed(event.target.checked)} />
            <span><strong>我已有经过核验的兼容闭测构建</strong><small>确认构建版本不低于 v{minimumDaemonVersion}，来源和 SHA-256 已由管理员单独提供并核对。</small></span>
          </label>
        </div>
      )}
      <label><span>主机名称</span><input value={name} onChange={(event) => setName(event.target.value)} placeholder="例如：家里工作站" minLength={2} maxLength={48} required /><small>这是控制台显示名，不会成为任意路径输入。</small></label>
      <fieldset><legend>操作系统</legend><div className="choice-grid"><label className={os === "windows" ? "selected" : ""}><input type="radio" name="os" value="windows" checked={os === "windows"} onChange={() => setOs("windows")} /><strong>Windows</strong><small>amd64 · 正式支持</small></label><label className={os === "linux" ? "selected" : ""}><input type="radio" name="os" value="linux" checked={os === "linux"} onChange={() => setOs("linux")} /><strong>Linux</strong><small>amd64 / arm64 · 正式支持</small></label></div></fieldset>
      {error && <p className="form-error" role="alert">{error}</p>}
      <button className="button button-primary" type="submit" disabled={loading || (!releaseAvailable && !closedBetaBuildConfirmed)}>{loading ? "正在创建…" : "生成 10 分钟配对码"}</button>
    </form>
  );
}
