import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { RetrievalBench } from "../components/RetrievalBench";
import { adminDatasources, listModels, migrateKbStorage, type DatasourceKB, type MigrateKbResult } from "../api";

// 数据源 & RAG：真数据(全平台知识库清单，来自 sundynix_kb/sundynix_doc)。
const KIND_LABEL: Record<string, string> = { general: "通用", folder: "文件夹", project: "项目", case: "案例" };
const fmtWords = (n: number) => (n >= 1e4 ? `${(n / 1e4).toFixed(1)}万` : `${n}`);

export function DatasourcesPage() {
  const [counts, setCounts] = useState({ users: 0, kbs: 0, docs: 0 });
  const [rows, setRows] = useState<DatasourceKB[]>([]);
  const [loading, setLoading] = useState(true);
  const [err, setErr] = useState("");
  
  // 运行时的 active embedding 模型展示
  const [activeEmbedding, setActiveEmbedding] = useState<string>("加载中…");
  
  // 运维工具折叠状态
  const [opsOpen, setOpsOpen] = useState(false);
  
  // 迁移 Modal 状态
  const [migrationModal, setMigrationModal] = useState<"none" | "confirm" | "running" | "done">("none");
  const [migrationResult, setMigrationResult] = useState<MigrateKbResult | null>(null);
  const [migrationErr, setMigrationErr] = useState("");

  useEffect(() => {
    adminDatasources()
      .then((r) => {
        setCounts(r.counts);
        setRows(r.datasources);
        setErr("");
      })
      .catch((e) => setErr((e as Error).message))
      .finally(() => setLoading(false));

    // 获取激活的 embedding 模型
    listModels("embedding")
      .then((models) => {
        const active = models.find((m) => m.active);
        if (active) {
          setActiveEmbedding(`${active.model} (${active.provider})`);
        } else {
          setActiveEmbedding("未配置/未激活 (将回退代码默认)");
        }
      })
      .catch(() => setActiveEmbedding("获取失败"));
  }, []);

  const startMigration = async () => {
    setMigrationModal("running");
    setMigrationErr("");
    try {
      const res = await migrateKbStorage();
      setMigrationResult(res);
      setMigrationModal("done");
    } catch (e) {
      setMigrationErr((e as Error).message);
      setMigrationModal("confirm"); // 退回到确认态展示错误
    }
  };

  const totalWords = rows.reduce((a, r) => a + r.total_words, 0);

  return (
    <div className="flex flex-col gap-6">
      {/* 顶部激活模型只读展示 & 引导 */}
      <div className="rounded-xl border border-gray-100 bg-white p-5 shadow-sm flex items-center justify-between">
        <div>
          <h4 className="text-sm font-semibold text-gray-700">当前激活向量化模型 (Embedding)</h4>
          <div className="mt-1 flex items-center gap-2">
            <span className="h-2 w-2 rounded-full bg-emerald-500 animate-pulse"></span>
            <code className="text-xs font-mono font-medium text-gray-800">{activeEmbedding}</code>
          </div>
        </div>
        <Link
          to="/admin/models"
          className="flex items-center gap-1 text-xs font-medium text-violet-600 hover:text-violet-700 hover:underline"
        >
          前往「模型配置」修改 →
        </Link>
      </div>

      {/* 运维工具 (RAG 迁移) */}
      <div className="rounded-xl border border-gray-100 bg-white p-5 shadow-sm">
        <button
          onClick={() => setOpsOpen(!opsOpen)}
          className="flex w-full items-center justify-between font-semibold text-gray-700 focus:outline-none"
        >
          <div className="flex items-center gap-2">
            <svg className="h-4 w-4 text-amber-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
            </svg>
            <span className="text-sm font-semibold text-gray-700">运维工具</span>
          </div>
          <span className="text-xs text-gray-400">{opsOpen ? "收起 ▲" : "展开 ▼"}</span>
        </button>

        {opsOpen && (
          <div className="mt-4 border-t border-gray-100 pt-4 space-y-4">
            <div className="flex flex-col md:flex-row md:items-center justify-between gap-3 text-xs bg-amber-50/50 border border-amber-100 p-4 rounded-lg">
              <div className="space-y-1">
                <div className="font-semibold text-amber-800 flex items-center gap-1.5">
                  <span>知识库存储目录路径迁移</span>
                  <span className="bg-amber-100 text-amber-700 px-1.5 py-0.5 rounded text-[9px] font-bold">建议在低峰期操作</span>
                </div>
                <p className="text-gray-500 leading-relaxed max-w-xl">
                  将平台全量知识库底层的存储目录规范，由早期版本的 <code className="bg-gray-100 px-1 rounded">owner/kb_id/doc</code> 升级为新版本统一的 <code className="bg-gray-100 px-1 rounded">space_id/kb_id/doc</code> 规范。此操作将遍历所有文件，并在数据库与对象存储中更新映射关系，迁移期间可能产生轻微检索延迟。
                </p>
              </div>
              <button
                onClick={() => setMigrationModal("confirm")}
                className="self-start md:self-center shrink-0 bg-amber-600 hover:bg-amber-700 text-white text-xs font-semibold py-2 px-4 rounded-lg shadow-sm transition"
              >
                开始迁移
              </button>
            </div>
          </div>
        )}
      </div>

      {/* 迁移 Modal */}
      {migrationModal !== "none" && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 backdrop-blur-sm">
          <div className="relative mx-4 w-full max-w-md overflow-hidden rounded-2xl bg-white shadow-2xl">
            <div className="flex items-center justify-between border-b border-gray-100 px-6 py-5">
              <div>
                <h3 className="text-base font-semibold text-gray-900">
                  {migrationModal === "confirm" && "确认开始存储迁移？"}
                  {migrationModal === "running" && "正在迁移中…"}
                  {migrationModal === "done" && "迁移完成 🎉"}
                </h3>
                <p className="mt-0.5 text-xs text-gray-400">一键升级平台 KB 作用域至 space_id</p>
              </div>
              {migrationModal !== "running" && (
                <button
                  onClick={() => setMigrationModal("none")}
                  className="text-xl leading-none text-gray-400 hover:text-gray-600"
                >
                  ×
                </button>
              )}
            </div>

            <div className="space-y-4 px-6 py-5 text-sm">
              {migrationModal === "confirm" && (
                <>
                  <p className="text-gray-600 leading-relaxed">
                    您将触发全平台的数据目录热迁移。这会将旧版未挂载空间的独立知识库映射，统一调整至 Space 空间映射下。
                  </p>
                  <div className="rounded-lg border border-amber-100 bg-amber-50 p-3 text-xs text-amber-700 space-y-1">
                    <div className="font-semibold">⚠️ 运维安全警示：</div>
                    <div>· 这是一个高危数据库与存储热变更操作</div>
                    <div>· 建议执行前对 <code className="font-mono bg-amber-100/50 px-1">sundynix_doc</code> 表进行备份</div>
                    <div>· 确认执行后不可中途停止</div>
                  </div>
                  {migrationErr && (
                    <div className="rounded-lg border border-rose-100 bg-rose-50 px-3 py-2 text-xs text-rose-600">
                      操作失败：{migrationErr}
                    </div>
                  )}
                </>
              )}

              {migrationModal === "running" && (
                <div className="flex flex-col items-center justify-center py-6 space-y-3">
                  <svg className="animate-spin h-8 w-8 text-amber-600" fill="none" viewBox="0 0 24 24">
                    <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
                    <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
                  </svg>
                  <span className="text-xs text-gray-500 font-medium animate-pulse">正在扫描文档并重新入队，请勿关闭窗口…</span>
                </div>
              )}

              {migrationModal === "done" && migrationResult && (
                <div className="space-y-3">
                  <div className="rounded-lg border border-emerald-100 bg-emerald-50 px-3 py-2 text-xs text-emerald-700">
                    数据升级指令已成功执行，各文档已重新入队执行 RRF 索引重灌。
                  </div>
                  <div className="divide-y divide-gray-100 border rounded-xl overflow-hidden bg-gray-50/50">
                    <div className="flex justify-between p-3 text-xs">
                      <span className="text-gray-500">已扫描文档总数</span>
                      <span className="font-semibold text-gray-800 font-mono">{migrationResult.total}</span>
                    </div>
                    <div className="flex justify-between p-3 text-xs">
                      <span className="text-gray-500">入队重灌文档数</span>
                      <span className="font-semibold text-amber-600 font-mono">{migrationResult.enqueued}</span>
                    </div>
                    <div className="flex justify-between p-3 text-xs">
                      <span className="text-gray-500">跳过（已是新作用域）</span>
                      <span className="font-semibold text-gray-600 font-mono">{migrationResult.skipped}</span>
                    </div>
                  </div>
                </div>
              )}
            </div>

            <div className="flex items-center justify-end gap-2 border-t border-gray-100 px-6 py-4">
              {migrationModal === "confirm" && (
                <>
                  <button
                    onClick={() => setMigrationModal("none")}
                    className="rounded-lg border border-gray-200 px-4 py-2 text-xs text-gray-500 hover:bg-gray-50"
                  >
                    取消
                  </button>
                  <button
                    onClick={() => void startMigration()}
                    className="rounded-lg bg-amber-600 hover:bg-amber-700 px-4 py-2 text-xs font-semibold text-white shadow-sm transition"
                  >
                    确认迁移
                  </button>
                </>
              )}
              {migrationModal === "done" && (
                <button
                  onClick={() => setMigrationModal("none")}
                  className="rounded-lg bg-violet-600 hover:bg-violet-700 px-4 py-2 text-xs font-semibold text-white shadow-sm transition"
                >
                  我知道了
                </button>
              )}
            </div>
          </div>
        </div>
      )}


      {/* 检索管线说明（诚实：三路 + RRF 等权融合，非可调权重） */}
      <div className="rounded-xl border border-gray-100 bg-white p-5 shadow-sm">
        <h3 className="mb-3 text-sm font-semibold text-gray-700">混合检索管线</h3>
        <div className="grid grid-cols-1 gap-3 md:grid-cols-3">
          <Route color="violet" name="向量检索" impl="Milvus" desc="Embedding 相似度召回语义相关块" />
          <Route color="cyan" name="全文检索" impl="Bleve" desc="倒排索引召回关键词精确命中" />
          <Route color="emerald" name="图谱检索" impl="Neo4j" desc="实体三元组召回结构化关联" />
        </div>
        <p className="mt-3 text-[11px] leading-relaxed text-gray-400">
          三路并行召回 → <span className="font-medium text-gray-600">RRF 倒排互惠融合</span>（Reciprocal Rank Fusion，平滑常数 k=60）→ rerank 重排。
          融合按各路排名等权，无「每路占几成」的可调权重；单路可经 <code className="rounded bg-gray-100 px-1">SearchByMode</code> 指定。检索参数定义在 mcp-go 代码中。
        </p>
      </div>

      {/* 检索试验台：紧跟管线说明 —— 讲完原理就能当场验证，不用只看文字 */}
      <RetrievalBench kbs={rows} />

      {/* 平台数据源计数 */}
      <div className="grid grid-cols-3 gap-4">
        <Stat label="知识库" value={String(counts.kbs)} tone="violet" />
        <Stat label="文档总数" value={String(counts.docs)} tone="cyan" sub={`约 ${fmtWords(totalWords)} 字`} />
        <Stat label="平台用户" value={String(counts.users)} tone="emerald" />
      </div>

      {/* 知识库清单（真数据） */}
      <div className="rounded-xl border border-gray-100 bg-white p-5 shadow-sm">
        <h3 className="mb-3 text-sm font-semibold text-gray-700">知识库清单（全平台）</h3>
        {loading ? (
          <div className="py-8 text-center text-xs text-gray-400">加载中…</div>
        ) : err ? (
          <div className="py-8 text-center text-xs text-rose-500">加载失败：{err}</div>
        ) : rows.length === 0 ? (
          <div className="py-8 text-center text-xs text-gray-400">还没有知识库</div>
        ) : (
          <div className="overflow-x-auto">
            <table className="w-full text-sm">
              <thead>
                <tr className="border-b border-gray-100 text-left text-[11px] uppercase tracking-wide text-gray-400">
                  <th className="py-2 pr-3 font-medium">知识库</th>
                  <th className="py-2 pr-3 font-medium">类型</th>
                  <th className="py-2 pr-3 font-medium">租户</th>
                  <th className="py-2 pr-3 text-right font-medium">文档数</th>
                  <th className="py-2 text-right font-medium">总字数</th>
                </tr>
              </thead>
              <tbody>
                {rows.map((r) => (
                  <tr key={r.id} className="border-b border-gray-50 last:border-0">
                    <td className="py-2 pr-3 font-medium text-gray-800">{r.name}</td>
                    <td className="py-2 pr-3"><span className="rounded bg-gray-100 px-1.5 py-0.5 text-[10px] text-gray-600">{KIND_LABEL[r.kind] ?? r.kind}</span></td>
                    <td className="py-2 pr-3 text-xs text-gray-500">{r.tenant_name || r.tenant_id || "—"}</td>
                    <td className="py-2 pr-3 text-right tabular-nums text-gray-700">{r.doc_count}</td>
                    <td className="py-2 text-right tabular-nums text-gray-500">{fmtWords(r.total_words)}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
      </div>
    </div>
  );
}

const ROUTE_TONE: Record<string, { dot: string; text: string }> = {
  violet: { dot: "bg-violet-500", text: "text-violet-600" },
  cyan: { dot: "bg-cyan-500", text: "text-cyan-600" },
  emerald: { dot: "bg-emerald-500", text: "text-emerald-600" },
};
function Route({ color, name, impl, desc }: { color: string; name: string; impl: string; desc: string }) {
  const t = ROUTE_TONE[color];
  return (
    <div className="rounded-lg border border-gray-100 bg-gray-50/50 p-3">
      <div className="flex items-center gap-2">
        <span className={`h-2 w-2 rounded-full ${t.dot}`} />
        <span className="text-sm font-medium text-gray-700">{name}</span>
        <span className={`text-[10px] ${t.text}`}>{impl}</span>
      </div>
      <p className="mt-1 text-[11px] leading-relaxed text-gray-500">{desc}</p>
    </div>
  );
}

const STAT_TONE: Record<string, string> = { violet: "text-violet-600", cyan: "text-cyan-600", emerald: "text-emerald-600" };
function Stat({ label, value, sub, tone }: { label: string; value: string; sub?: string; tone: string }) {
  return (
    <div className="rounded-xl border border-gray-100 bg-white p-4 shadow-sm">
      <div className="text-xs text-gray-400">{label}</div>
      <div className={`mt-1 text-2xl font-semibold tabular-nums ${STAT_TONE[tone] ?? "text-gray-800"}`}>{value}</div>
      {sub && <div className="mt-1 text-[11px] text-gray-400">{sub}</div>}
    </div>
  );
}
