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

import type { AdminDiagnosticsResponse, AdminServicesStorageResponse } from "@dada/shared-contracts";

import "./admin-services-storage.css";

const serviceLabels: Record<AdminServicesStorageResponse["services"][number]["service_id"], string> = {
  ai_gateway: "AI 网关",
  amap: "高德",
  api: "API",
  asset_root: "素材根",
  resend: "Resend",
  worker: "Worker",
};

const statusLabels: Record<AdminServicesStorageResponse["services"][number]["status"], string> = {
  active: "正常",
  degraded: "有异常",
  disabled: "已停用",
  paused_provider: "供应商暂停",
  paused_quota: "额度暂停",
  unavailable: "不可用",
};

const impactLabels: Record<AdminServicesStorageResponse["services"][number]["impact_scope"], string> = {
  account: "账户模型",
  api: "后台接口",
  authentication: "认证",
  generation: "生成",
  location: "定位",
  model: "单模型",
  none: "无",
  storage: "存储",
  unknown: "未知范围",
};

function formatTime(value: string | null) {
  if (!value) return "未记录";
  return new Intl.DateTimeFormat("zh-CN", { dateStyle: "short", timeStyle: "short" }).format(new Date(value));
}

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

export function AdminServicesStoragePage() {
  const [state, setState] = useState<AdminServicesStorageResponse>();
  const [diagnostics, setDiagnostics] = useState<AdminDiagnosticsResponse>();
  const [loading, setLoading] = useState(true);
  const [failed, setFailed] = useState(false);
  const [copied, setCopied] = useState(false);

  const load = useCallback(async () => {
    setLoading(true);
    setFailed(false);
    try {
      const [nextState, nextDiagnostics] = await Promise.all([
        getJson<AdminServicesStorageResponse>("/api/v1/admin/services-storage"),
        getJson<AdminDiagnosticsResponse>("/api/v1/admin/diagnostics"),
      ]);
      setState(nextState);
      setDiagnostics(nextDiagnostics);
    } catch {
      setFailed(true);
    } finally {
      setLoading(false);
    }
  }, []);

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

  async function copyDiagnostics() {
    if (!diagnostics) return;
    try {
      await navigator.clipboard.writeText(diagnostics.diagnostic_text);
      setCopied(true);
      window.setTimeout(() => setCopied(false), 1800);
    } catch {
      setCopied(false);
    }
  }

  return (
    <main className="admin-services-storage" id="admin-main">
      <header className="admin-page-heading admin-services-heading">
        <div><p>OPERATIONS / HEALTH</p><h2>服务与存储</h2></div>
        <div className="admin-services-heading-actions">
          {state ? <time dateTime={state.generated_at}>更新于 {formatTime(state.generated_at)}</time> : null}
          <button aria-label="重新读取服务与存储状态" onClick={() => void load()} type="button">重新读取</button>
        </div>
      </header>
      {loading && !state ? <div aria-label="服务与存储状态加载中" className="admin-services-loading"><span /><span /><span /><span /></div> : null}
      {failed ? <div className="admin-services-failure" role="alert"><span>状态暂时无法读取{state ? `，保留 ${formatTime(state.generated_at)} 的结果` : ""}。</span><button onClick={() => void load()} type="button">重试</button></div> : null}
      {state ? (
        <>
          <section aria-labelledby="admin-services-list-heading" className="admin-health-section">
            <header><div><p>SERVICE STATUS</p><h3 id="admin-services-list-heading">外部服务与本机组件</h3></div><span className="admin-safe-note">仅显示脱敏状态</span></header>
            <div className="admin-service-grid">
              {state.services.map((service) => (
                <article className={`admin-service-card is-${service.status}`} key={service.service_id}>
                  <div className="admin-service-card-heading"><strong>{serviceLabels[service.service_id]}</strong><span>{statusLabels[service.status]}</span></div>
                  <dl>
                    <div><dt>配置状态</dt><dd>{service.configured ? "已配置" : "未配置"}</dd></div>
                    <div><dt>影响范围</dt><dd>{impactLabels[service.impact_scope]}</dd></div>
                    <div><dt>最近检查</dt><dd>{formatTime(service.checked_at)}</dd></div>
                    {service.pause_reason ? <div><dt>安全原因</dt><dd>{service.pause_reason}</dd></div> : null}
                  </dl>
                </article>
              ))}
            </div>
          </section>
          <section aria-labelledby="admin-storage-heading" className="admin-health-section">
            <header><div><p>LOCAL DATA ROOT</p><h3 id="admin-storage-heading">本机内容容量</h3></div><span className={`admin-storage-state is-${state.storage.status}`}>{state.storage.status === "active" ? "可写" : state.storage.status === "full" ? "已满" : "不可用"}</span></header>
            <div className="admin-storage-metrics">
              <div><span>已用内容</span><strong>{(state.storage.managed_content_bytes / 1024 / 1024 / 1024).toFixed(2)} GB</strong></div>
              <div><span>固定上限</span><strong>{(state.storage.hard_limit_bytes / 1024 / 1024 / 1024).toFixed(2)} GB</strong></div>
              <div><span>容量提醒</span><strong>{state.storage.capacity_notice_level}</strong></div>
              <div><span>清理队列</span><strong>{state.storage.cleanup_pending_count}</strong></div>
            </div>
            <div className="admin-storage-progress" aria-label={`本机内容容量 ${(state.storage.managed_content_bytes / state.storage.hard_limit_bytes * 100).toFixed(1)}%`}><span style={{ width: `${Math.min(100, state.storage.managed_content_bytes / state.storage.hard_limit_bytes * 100)}%` }} /></div>
            <p className="admin-storage-description">测试数据仅保存在本机，不自动备份，也不会迁移到正式系统。当前 Windows 用户的 Dada 本机数据目录引用：<code>{state.storage.data_root_ref}</code>。只读规范素材库不计入 5 GB 内容额度。</p>
            <dl className="admin-storage-details"><div><dt>最后计量</dt><dd>{formatTime(state.storage.last_measured_at)}</dd></div><div><dt>重新计量</dt><dd>{state.storage.remeasurement_required ? "需要完成" : "无需等待"}</dd></div></dl>
          </section>
          <section aria-labelledby="admin-diagnostics-heading" className="admin-health-section admin-diagnostics-section">
            <header><div><p>DIAGNOSTICS</p><h3 id="admin-diagnostics-heading">脱敏诊断</h3></div><button disabled={!diagnostics} onClick={() => void copyDiagnostics()} type="button">{copied ? "已复制" : "复制诊断"}</button></header>
            <p>诊断内容只包含固定版本、组件状态、逻辑位置和容量计量，不包含密钥、邮箱、绝对路径、提示词、图片或供应商原文。</p>
            {diagnostics ? <pre aria-label="脱敏诊断内容">{diagnostics.diagnostic_text}</pre> : <div aria-label="诊断加载中" className="admin-diagnostics-placeholder" />}
          </section>
        </>
      ) : null}
    </main>
  );
}
