import { useCallback, useEffect, useState } from "react";

import { LocalOnlyFooter, ProductHeader } from "./project-pages.js";

import "./credits-page.css";

type EntryType = "registration_grant" | "generation_reserve" | "generation_commit" | "generation_release" | "admin_adjustment";

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

interface LedgerEntry {
  amount: number;
  available_after: number;
  available_before: number;
  created_at: string;
  entry_id: string;
  entry_type: EntryType;
  model_id: string | null;
  reason: string | null;
  reference_id: string | null;
  reference_type: "registration" | "generation" | "admin_adjustment" | null;
  reserved_after: number;
  reserved_before: number;
  status: "succeeded" | "frozen" | "committed" | "released";
}

interface LedgerResponse {
  credits: Pick<CreditBalance, "available_balance" | "reserved_balance">;
  entries: LedgerEntry[];
  next_cursor: string | null;
  updated_at: string;
}

const entryLabels: Record<EntryType, string> = {
  admin_adjustment: "管理员调整",
  generation_commit: "生成结算",
  generation_release: "生成释放",
  generation_reserve: "生成冻结",
  registration_grant: "注册赠点",
};

const statusLabels = {
  committed: "已结算",
  frozen: "已冻结",
  released: "已释放",
  succeeded: "已完成",
} as const;

async function readJson<T>(url: string) {
  const response = await fetch(url, { credentials: "same-origin" });
  if (response.status === 401) {
    window.dispatchEvent(new Event("dada:session-invalid"));
    throw new Error("session_invalid");
  }
  if (!response.ok) throw new Error("request_failed");
  return response.json() as Promise<T>;
}

function localTime(value: string) {
  return new Intl.DateTimeFormat("zh-CN", { dateStyle: "medium", timeStyle: "short" }).format(new Date(value));
}

export function CreditsPage() {
  const [balance, setBalance] = useState<CreditBalance>();
  const [entries, setEntries] = useState<LedgerEntry[]>([]);
  const [nextCursor, setNextCursor] = useState<string | null>(null);
  const [eventType, setEventType] = useState<EntryType | "">("");
  const [from, setFrom] = useState("");
  const [to, setTo] = useState("");
  const [loading, setLoading] = useState(true);
  const [loadingMore, setLoadingMore] = useState(false);
  const [failed, setFailed] = useState(false);

  const load = useCallback(async (cursor?: string) => {
    const query = new URLSearchParams({ limit: "20" });
    if (cursor) query.set("cursor", cursor);
    if (eventType) query.set("event_type", eventType);
    if (from) query.set("from", new Date(`${from}T00:00:00`).toISOString());
    if (to) query.set("to", new Date(`${to}T23:59:59.999`).toISOString());
    if (cursor) setLoadingMore(true); else setLoading(true);
    setFailed(false);
    try {
      const [nextBalance, ledger] = await Promise.all([
        readJson<CreditBalance>("/api/v1/me/credits"),
        readJson<LedgerResponse>(`/api/v1/me/credit-ledger?${query}`),
      ]);
      setBalance(nextBalance);
      setEntries((current) => cursor ? [...current, ...ledger.entries] : ledger.entries);
      setNextCursor(ledger.next_cursor);
    } catch (error) {
      if (!(error instanceof Error) || error.message !== "session_invalid") setFailed(true);
    } finally {
      setLoading(false);
      setLoadingMore(false);
    }
  }, [eventType, from, to]);

  useEffect(() => { void load(); }, [load]);

  return (
    <div className="product-page">
      <ProductHeader current="credits" />
      <main className="credits-page">
        <header className="credits-heading">
          <div><p>ACCOUNT CREDIT</p><h1>点数明细</h1></div>
          {balance ? <time dateTime={balance.updated_at}>更新于 {localTime(balance.updated_at)}</time> : null}
        </header>
        {balance ? (
          <section className="credit-summary" aria-label="点数余额">
            <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><small>已冻结 {balance.reserved_balance} 点</small></div>
            <p>可用点数不足时，请联系管理员调整点数。</p>
          </section>
        ) : null}
        {failed ? <p className="credits-error" role="alert">点数读取失败。{balance ? "当前保留上次余额，提交时仍以服务端实时校验为准。" : "请重新读取。"}</p> : null}
        <section className="credit-ledger" aria-labelledby="ledger-title">
          <header>
            <h2 id="ledger-title">变动记录</h2>
            <div className="credit-filters">
              <label>事件类型
                <select value={eventType} onChange={(event) => setEventType(event.target.value as EntryType | "")}>
                  <option value="">全部事件</option>
                  {Object.entries(entryLabels).map(([value, label]) => <option key={value} value={value}>{label}</option>)}
                </select>
              </label>
              <label>开始日期<input type="date" value={from} onChange={(event) => setFrom(event.target.value)} /></label>
              <label>结束日期<input type="date" value={to} onChange={(event) => setTo(event.target.value)} /></label>
            </div>
          </header>
          {loading && entries.length === 0 ? <p className="ledger-empty" aria-live="polite">正在读取点数记录</p> : null}
          {!loading && entries.length === 0 && !failed ? <p className="ledger-empty">暂无点数变动</p> : null}
          {entries.length > 0 ? (
            <div className="credit-table-wrap">
              <table>
                <thead><tr><th>时间</th><th>事件</th><th>状态</th><th>变动</th><th>关联</th><th>余额</th></tr></thead>
                <tbody>
                  {entries.map((entry) => (
                    <tr key={entry.entry_id}>
                      <td><time dateTime={entry.created_at}>{localTime(entry.created_at)}</time></td>
                      <td><strong>{entryLabels[entry.entry_type]}</strong>{entry.reason ? <small>{entry.reason}</small> : null}</td>
                      <td>{statusLabels[entry.status]}</td>
                      <td className={entry.amount < 0 ? "is-negative" : "is-positive"}>变动 {entry.amount > 0 ? `+${entry.amount}` : entry.amount}</td>
                      <td>{entry.reference_type === "generation" ? "生成任务" : entry.reference_type === "admin_adjustment" ? "管理操作" : "注册"}</td>
                      <td>可用 {entry.available_after} / 冻结 {entry.reserved_after}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          ) : null}
          {nextCursor ? <button className="ledger-more" disabled={loadingMore} onClick={() => void load(nextCursor)} type="button">{loadingMore ? "加载中" : "加载更多"}</button> : null}
          {failed ? <button className="ledger-retry" onClick={() => void load()} type="button">重新读取</button> : null}
        </section>
      </main>
      <LocalOnlyFooter />
    </div>
  );
}
