"use client";

import {
  ArrowClockwiseIcon,
  CheckCircleIcon,
  DatabaseIcon,
  FloppyDiskIcon,
  KeyIcon,
  PlugIcon,
  WarningCircleIcon,
  XIcon,
} from "@phosphor-icons/react";
import { useEffect, useMemo, useState } from "react";

import type {
  SettingField,
  SettingsReadiness,
  SettingsResponse,
  TestResult,
} from "@/types/settings";

const API_BASE = process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8000";

const testLabels: Record<string, string> = {
  infrastructure: "测试数据库与队列",
  storage: "测试 MinIO",
  baidu_ocr: "测试百度 OCR",
  ai_models: "验证 API 与模型",
  gpu: "测试 GPU Worker",
  langfuse: "测试 Langfuse",
  sentry: "测试 Sentry",
};

type SettingsCenterProps = {
  open: boolean;
  onClose: () => void;
  onReadinessChange: (readiness: SettingsReadiness) => void;
};

function isVisible(field: SettingField, draft: Record<string, unknown>) {
  if (!field.visible_when) return true;
  return Object.entries(field.visible_when).every(([key, expected]) => {
    if (key.endsWith("__not")) return draft[key.slice(0, -5)] !== expected;
    return draft[key] === expected;
  });
}

function getErrorMessage(error: unknown) {
  return error instanceof Error ? error.message : "请求失败，请检查 API 服务是否启动。";
}

export function SettingsCenter({ open, onClose, onReadinessChange }: SettingsCenterProps) {
  const [data, setData] = useState<SettingsResponse | null>(null);
  const [draft, setDraft] = useState<Record<string, unknown>>({});
  const [activeCategoryId, setActiveCategoryId] = useState("deployment");
  const [showAdvanced, setShowAdvanced] = useState(false);
  const [busy, setBusy] = useState<string | null>(null);
  const [notice, setNotice] = useState<{ tone: "success" | "error"; text: string } | null>(null);
  const [testResults, setTestResults] = useState<Record<string, TestResult>>({});

  const activeCategory = useMemo(
    () => data?.categories.find((category) => category.id === activeCategoryId) ?? data?.categories[0],
    [activeCategoryId, data],
  );

  function applyResponse(response: SettingsResponse) {
    setData(response);
    setDraft(response.values);
    onReadinessChange(response.readiness);
  }

  async function loadSettings() {
    setBusy("load");
    setNotice(null);
    try {
      const response = await fetch(`${API_BASE}/v1/settings`, { cache: "no-store" });
      if (!response.ok) throw new Error("系统设置读取失败。请确认后端 API 已启动。");
      applyResponse(await response.json() as SettingsResponse);
    } catch (error) {
      setNotice({ tone: "error", text: getErrorMessage(error) });
    } finally {
      setBusy(null);
    }
  }

  useEffect(() => {
    if (!open) return;
    let cancelled = false;
    fetch(`${API_BASE}/v1/settings`, { cache: "no-store" })
      .then((response) => {
        if (!response.ok) throw new Error("系统设置读取失败。请确认后端 API 已启动。");
        return response.json() as Promise<SettingsResponse>;
      })
      .then((response) => {
        if (cancelled) return;
        setData(response);
        setDraft(response.values);
        onReadinessChange(response.readiness);
      })
      .catch((error: unknown) => {
        if (!cancelled) setNotice({ tone: "error", text: getErrorMessage(error) });
      });
    return () => { cancelled = true; };
  }, [open, onReadinessChange]);

  function updateField(key: string, value: unknown) {
    setDraft((current) => ({ ...current, [key]: value }));
    setNotice(null);
  }

  async function saveSettings(showSuccess = true) {
    setBusy("save");
    setNotice(null);
    try {
      const response = await fetch(`${API_BASE}/v1/settings`, {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ values: draft }),
      });
      if (!response.ok) throw new Error("保存失败，请检查填写内容。");
      const payload = await response.json() as SettingsResponse;
      applyResponse(payload);
      if (showSuccess) setNotice({ tone: "success", text: "设置已加密保存。" });
      return payload;
    } catch (error) {
      setNotice({ tone: "error", text: getErrorMessage(error) });
      throw error;
    } finally {
      setBusy(null);
    }
  }

  async function testTarget(target: string) {
    setBusy(target);
    setNotice(null);
    try {
      await saveSettings(false);
      setBusy(target);
      const response = await fetch(`${API_BASE}/v1/settings/test`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ target, values: {} }),
      });
      const result = await response.json() as TestResult;
      setTestResults((current) => ({ ...current, [target]: result }));
      await loadSettings();
      setNotice({ tone: result.ok ? "success" : "error", text: result.message });
    } catch (error) {
      setNotice({ tone: "error", text: getErrorMessage(error) });
    } finally {
      setBusy(null);
    }
  }

  async function generateFor(field: SettingField) {
    if (!field.generator) return;
    setBusy(field.key);
    try {
      const response = await fetch(`${API_BASE}/v1/settings/generate-secret`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ kind: field.generator }),
      });
      if (!response.ok) throw new Error("密钥生成失败。");
      const payload = await response.json() as { value: string };
      updateField(field.key, payload.value);
      setNotice({ tone: "success", text: `${field.label}已生成，点击保存后会加密存储。` });
    } catch (error) {
      setNotice({ tone: "error", text: getErrorMessage(error) });
    } finally {
      setBusy(null);
    }
  }

  function closeSafely() {
    if (data) {
      const secretKeys = new Set(data.categories.flatMap((category) => category.fields)
        .filter((field) => field.secret)
        .map((field) => field.key));
      setDraft((current) => Object.fromEntries(
        Object.entries(current).filter(([key]) => !secretKeys.has(key)),
      ));
    }
    onClose();
  }

  if (!open) return null;

  return (
    <div className="settings-backdrop" role="presentation">
      <section className="settings-dialog" role="dialog" aria-modal="true" aria-label="系统设置">
        <header className="settings-header">
          <div>
            <p className="settings-kicker">首次使用向导</p>
            <h1>系统设置</h1>
            <p>只填写你真正使用的服务；密钥保存后不会再次显示。</p>
          </div>
          <button className="icon-button" type="button" onClick={closeSafely} aria-label="关闭系统设置">
            <XIcon size={18} />
          </button>
        </header>

        {data ? (
          <div className="settings-readiness">
            <div className={`readiness-orb ${data.readiness.ready ? "ready" : ""}`}>
              {data.readiness.ready ? <CheckCircleIcon size={22} weight="fill" /> : <DatabaseIcon size={22} />}
            </div>
            <div>
              <strong>{data.readiness.ready ? "工作流已就绪" : "完成必备配置后才能开始设计"}</strong>
              <p>{data.readiness.completed_required} / {data.readiness.total_required} 个必备分类已配置并测试</p>
            </div>
            <div className="readiness-meter" aria-label="配置完成度">
              <span style={{ width: `${(data.readiness.completed_required / data.readiness.total_required) * 100}%` }} />
            </div>
          </div>
        ) : null}

        <div className="settings-layout">
          <nav className="settings-nav" aria-label="设置分类">
            {data?.categories.map((category) => {
              const categoryTested = category.test_targets.length === 0 || category.test_targets.every(
                (target) => data.tests[target]?.ok,
              );
              return (
                <button
                  key={category.id}
                  type="button"
                  className={category.id === activeCategory?.id ? "active" : ""}
                  onClick={() => setActiveCategoryId(category.id)}
                >
                  <span>{category.label}</span>
                  {category.required_for_workflow ? (
                    <small className={categoryTested ? "done" : "required"}>
                      {categoryTested ? "已测试" : "必备"}
                    </small>
                  ) : <small>可选</small>}
                </button>
              );
            })}
          </nav>

          <div className="settings-content">
            {busy === "load" && !data ? (
              <div className="settings-loading"><ArrowClockwiseIcon size={24} /> 正在读取设置</div>
            ) : activeCategory && data ? (
              <>
                <div className="settings-section-heading">
                  <div>
                    <h2>{activeCategory.label}</h2>
                    <p>{activeCategory.description}</p>
                  </div>
                  {activeCategory.fields.some((field) => field.advanced) ? (
                    <label className="advanced-toggle">
                      <input
                        type="checkbox"
                        checked={showAdvanced}
                        onChange={(event) => setShowAdvanced(event.target.checked)}
                      />
                      高级设置
                    </label>
                  ) : null}
                </div>

                <div className="settings-fields">
                  {activeCategory.fields.map((field) => {
                    if (!isVisible(field, draft) || (field.advanced && !showAdvanced)) return null;
                    return (
                      <SettingControl
                        key={field.key}
                        field={field}
                        value={draft[field.key]}
                        configured={Boolean(data.configured[field.key])}
                        onChange={(value) => updateField(field.key, value)}
                        onGenerate={() => void generateFor(field)}
                        busy={busy === field.key}
                      />
                    );
                  })}
                </div>

                {activeCategory.id === "deployment" ? (
                  <div className="deployment-note">
                    <KeyIcon size={18} />
                    <p>数据库和 Redis 密码存在“先有服务还是先打开设置页”的启动顺序问题，因此不在这里修改。运行 <code>scripts/bootstrap.ps1</code> 时会一次性安全生成，你不需要安装 OpenSSL。</p>
                  </div>
                ) : null}

                <div className="settings-test-actions">
                  {activeCategory.test_targets.map((target) => {
                    const recorded = testResults[target] ?? (data.tests[target] as TestResult | undefined);
                    return (
                      <button
                        className="button button-secondary"
                        type="button"
                        key={target}
                        onClick={() => void testTarget(target)}
                        disabled={Boolean(busy)}
                      >
                        {busy === target ? <ArrowClockwiseIcon className="spin" size={16} /> : <PlugIcon size={16} />}
                        {testLabels[target] ?? "测试连接"}
                        {recorded?.ok ? <CheckCircleIcon size={15} weight="fill" /> : null}
                      </button>
                    );
                  })}
                </div>
              </>
            ) : null}
          </div>
        </div>

        <footer className="settings-footer">
          <div className={`settings-notice ${notice?.tone ?? ""}`}>
            {notice?.tone === "error" ? <WarningCircleIcon size={17} /> : null}
            {notice?.tone === "success" ? <CheckCircleIcon size={17} weight="fill" /> : null}
            <span>{notice?.text ?? "必备项完成并测试通过后，设计工作流会自动解锁。"}</span>
          </div>
          <div className="settings-footer-actions">
            <button className="button button-secondary" type="button" onClick={closeSafely}>稍后设置</button>
            <button
              className="button button-primary"
              type="button"
              onClick={() => void saveSettings()}
              disabled={Boolean(busy) || !data}
            >
              <FloppyDiskIcon size={16} /> 保存设置
            </button>
          </div>
        </footer>
      </section>
    </div>
  );
}

type SettingControlProps = {
  field: SettingField;
  value: unknown;
  configured: boolean;
  onChange: (value: unknown) => void;
  onGenerate: () => void;
  busy: boolean;
};

function SettingControl({ field, value, configured, onChange, onGenerate, busy }: SettingControlProps) {
  const selectedOption = field.options.find((option) => option.value === String(value ?? ""));

  if (field.kind === "status") {
    return (
      <div className="setting-status-row">
        <span className={configured ? "configured" : "missing"}>
          {configured ? <CheckCircleIcon size={18} weight="fill" /> : <WarningCircleIcon size={18} />}
        </span>
        <div>
          <strong>{field.label}</strong>
          <p>{field.description}</p>
        </div>
        <small>{configured ? "已配置" : "缺失"}</small>
      </div>
    );
  }

  if (field.kind === "toggle") {
    return (
      <label className="setting-toggle-row">
        <div>
          <strong>{field.label}</strong>
          <p>{field.description}</p>
        </div>
        <input type="checkbox" checked={Boolean(value)} onChange={(event) => onChange(event.target.checked)} />
      </label>
    );
  }

  return (
    <label className="setting-field">
      <span className="setting-field-label">
        <strong>{field.label}</strong>
        {field.required ? <small>必填</small> : null}
      </span>
      <span className="setting-description">{field.description}</span>
      <span className="setting-control-wrap">
        {field.kind === "select" ? (
          <select value={String(value ?? "")} onChange={(event) => onChange(event.target.value)}>
            <option value="" disabled>请选择</option>
            {field.options.map((option) => <option key={option.value} value={option.value}>{option.label}</option>)}
          </select>
        ) : (
          <>
            <input
              type={field.kind === "password" ? "password" : field.kind === "number" ? "number" : "text"}
              list={field.kind === "combobox" ? `options-${field.key}` : undefined}
              value={String(value ?? "")}
              placeholder={field.secret && configured ? "已安全保存，留空不修改" : field.placeholder}
              onChange={(event) => onChange(event.target.value)}
              autoComplete="off"
            />
            {field.kind === "combobox" ? (
              <datalist id={`options-${field.key}`}>
                {field.options.map((option) => <option key={option.value} value={option.value}>{option.label}</option>)}
              </datalist>
            ) : null}
          </>
        )}
        {field.generator ? (
          <button className="generate-button" type="button" onClick={onGenerate} disabled={busy}>
            <KeyIcon size={14} /> 一键生成
          </button>
        ) : null}
      </span>
      {selectedOption ? <span className="option-help">{selectedOption.help}</span> : null}
    </label>
  );
}
