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

import "./admin-users.css";

interface AdminSession {
  csrf_token: string;
}

interface CreditBalance {
  available_balance: number;
  reserved_balance: number;
  updated_at: string;
}

async function readJson<T>(url: string, init?: RequestInit) {
  const response = await fetch(url, { credentials: "same-origin", ...init });
  if (response.status === 401) throw new Error("admin_session_invalid");
  if (!response.ok) throw new Error("request_failed");
  return response.json() as Promise<T>;
}

function idempotencyKey() {
  return crypto.randomUUID().replaceAll("-", "") + crypto.randomUUID().replaceAll("-", "");
}

export function AdminUsersPage() {
  const amountId = useId();
  const reasonId = useId();
  const userId = new URLSearchParams(window.location.search).get("userId") ?? "";
  const [session, setSession] = useState<AdminSession>();
  const [balance, setBalance] = useState<CreditBalance>();
  const [failed, setFailed] = useState(false);
  const [adjusting, setAdjusting] = useState(false);
  const [direction, setDirection] = useState<"increase" | "decrease">("increase");
  const [amount, setAmount] = useState("");
  const [reason, setReason] = useState("");
  const [adjustmentId, setAdjustmentId] = useState("");
  const [adjustmentKey, setAdjustmentKey] = useState("");
  const [submitting, setSubmitting] = useState(false);
  const [notice, setNotice] = useState("");

  useEffect(() => {
    if (!/^[0-9a-f-]{36}$/i.test(userId)) return;
    Promise.all([
      readJson<AdminSession>("/api/v1/admin-auth/session"),
      readJson<CreditBalance>(`/api/v1/admin/users/${userId}/credits`),
    ]).then(([nextSession, nextBalance]) => {
      setSession(nextSession);
      setBalance(nextBalance);
    }).catch(() => setFailed(true));
  }, [userId]);

  const signedAmount = useMemo(() => {
    const parsed = Number(amount);
    if (!Number.isSafeInteger(parsed) || parsed <= 0) return 0;
    return direction === "increase" ? parsed : -parsed;
  }, [amount, direction]);
  const projected = balance ? balance.available_balance + signedAmount : 0;

  function openAdjustment() {
    setDirection("increase");
    setAmount("");
    setReason("");
    setAdjustmentId(crypto.randomUUID());
    setAdjustmentKey(idempotencyKey());
    setAdjusting(true);
    setNotice("");
  }

  async function submitAdjustment(event: FormEvent) {
    event.preventDefault();
    if (!session || !balance || !adjustmentId || !adjustmentKey || signedAmount === 0 || !reason.trim() || submitting) return;
    setSubmitting(true);
    try {
      const result = await readJson<CreditBalance & { adjustment_id: string; status: "adjusted" }>(
        `/api/v1/admin/users/${userId}/credit-adjustments`,
        {
          body: JSON.stringify({ adjustment_id: adjustmentId, amount: signedAmount, reason: reason.trim() }),
          headers: {
            "Content-Type": "application/json",
            "Idempotency-Key": adjustmentKey,
            "X-CSRF-Token": session.csrf_token,
          },
          method: "POST",
        },
      );
      setBalance({
        available_balance: result.available_balance,
        reserved_balance: result.reserved_balance,
        updated_at: new Date().toISOString(),
      });
      setAdjusting(false);
      setNotice("点数调整已完成并记录审计");
    } catch {
      setNotice("点数调整未完成，请检查输入后重试");
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <div className="admin-users-page">
      <main id="admin-main">
        <header className="admin-users-heading">
          <div><p>USER OPERATIONS</p><h1>用户点数</h1></div>
          {balance ? <button onClick={openAdjustment} type="button">调整点数</button> : null}
        </header>
        {!userId ? <p className="admin-users-empty">从用户列表选择用户后调整点数。</p> : null}
        {failed ? <p className="admin-users-error" role="alert">用户点数暂时无法读取。</p> : null}
        {userId && !balance && !failed ? <p className="admin-users-empty" aria-live="polite">正在读取用户点数</p> : null}
        {balance ? (
          <section className="admin-credit-summary" aria-label="用户点数摘要">
            <div><span>内部用户标识</span><code>{userId}</code></div>
            <div><span>可用点数</span><strong className={balance.available_balance < 0 ? "is-negative" : undefined}>{balance.available_balance}</strong></div>
            <div><span>冻结点数</span><strong>{balance.reserved_balance}</strong></div>
          </section>
        ) : null}
        {notice ? <p className="admin-users-notice" role="status">{notice}</p> : null}
      </main>
      {adjusting && balance ? (
        <div className="credit-adjustment-overlay">
          <section aria-labelledby="adjustment-title" aria-modal="true" className="credit-adjustment-dialog" role="dialog">
            <p>CREDIT ADJUSTMENT</p>
            <h2 id="adjustment-title">调整点数</h2>
            <div className="adjustment-direction" role="radiogroup" aria-label="调整方向">
              <label><input checked={direction === "increase"} name="direction" onChange={() => setDirection("increase")} type="radio" />增加</label>
              <label><input checked={direction === "decrease"} name="direction" onChange={() => setDirection("decrease")} type="radio" />扣减</label>
            </div>
            <form onSubmit={submitAdjustment}>
              <label htmlFor={amountId}>调整数量</label>
              <input id={amountId} inputMode="numeric" min="1" onChange={(event) => setAmount(event.target.value.replace(/\D/g, ""))} type="number" value={amount} />
              <label htmlFor={reasonId}>调整原因</label>
              <textarea id={reasonId} maxLength={500} onChange={(event) => setReason(event.target.value)} value={reason} />
              <div className="adjustment-preview">
                <span>调整前可用点数 {balance.available_balance}</span>
                <strong>调整后可用点数 {projected}</strong>
                <span>冻结点数保持 {balance.reserved_balance}</span>
              </div>
              <div className="adjustment-actions">
                <button disabled={signedAmount === 0 || !reason.trim() || submitting} type="submit">{submitting ? "处理中" : "确认调整"}</button>
                <button disabled={submitting} onClick={() => setAdjusting(false)} type="button">取消</button>
              </div>
            </form>
          </section>
        </div>
      ) : null}
    </div>
  );
}
