"use client";

import Link from "next/link";
import { useEffect, useMemo, useState } from "react";

import { HintTip } from "@/components/hint-tip";
import { apiFetch } from "@/lib/api";
import { readToken } from "@/lib/auth";
import { useI18nText } from "@/lib/i18n";
import { formatUnixDateTime } from "@/lib/time";
import { Activity, HardDrive, Play, RefreshCw, Server } from "lucide-react";

type ImportJob = {
  id: number;
  status: string;
  trigger: string;
  total_count: number;
  processed_count: number;
  success_count: number;
  failed_count: number;
  options_json: string;
  last_error: string;
  started_at: number;
  finished_at: number | null;
  updated_at: number;
  created_at: number;
};

type ImportItem = {
  id: number;
  job_id: number;
  source_path: string;
  status: string;
  title: string;
  difficulty: number;
  problem_id: number | null;
  error_text: string;
  started_at: number | null;
  finished_at: number | null;
  updated_at: number;
  created_at: number;
};

type LatestResp = {
  runner_running: boolean;
  job: ImportJob | null;
};

type ItemsResp = {
  items: ImportItem[];
  page: number;
  page_size: number;
};

type MeProfile = {
  username?: string;
};

function fmtTs(v: number | null | undefined): string {
  return formatUnixDateTime(v);
}

type ImportJobOptions = {
  mode?: string;
  source?: string;
  workers?: number;
  target_total?: number;
  local_pdf_dir?: string;
  pdf_dir?: string;
};

function parseOptions(raw: string): ImportJobOptions | null {
  if (!raw) return null;
  try {
    const parsed = JSON.parse(raw);
    return typeof parsed === "object" && parsed !== null ? (parsed as ImportJobOptions) : null;
  } catch {
    return null;
  }
}

function statusToneClass(raw: string): string {
  const value = raw.toLowerCase();
  if (value.includes("queue") || value === "queued" || value === "pending") {
    return "mc-status-warning text-amber-700";
  }
  if (value.includes("run") || value === "running" || value === "processing") {
    return "mc-status-running text-blue-700";
  }
  if (value.includes("success") || value === "done" || value === "completed") {
    return "mc-status-success text-emerald-700";
  }
  if (value.includes("fail") || value === "failed" || value === "error") {
    return "mc-status-danger text-red-700";
  }
  return "mc-status-muted text-zinc-700";
}

export default function ImportsPage() {
  const { tx } = useI18nText();
  const [token, setToken] = useState("");
  const [checkingAdmin, setCheckingAdmin] = useState(true);
  const [isAdmin, setIsAdmin] = useState(false);
  const [runMode, setRunMode] = useState<"luogu" | "local_pdf_rag">("luogu");
  const [loading, setLoading] = useState(false);
  const [running, setRunning] = useState(false);
  const [error, setError] = useState("");
  const [job, setJob] = useState<ImportJob | null>(null);
  const [items, setItems] = useState<ImportItem[]>([]);
  const [statusFilter, setStatusFilter] = useState("");
  const [workers, setWorkers] = useState(3);
  const [localPdfDir, setLocalPdfDir] = useState("/data/local_pdfs");
  const [targetTotal, setTargetTotal] = useState(5000);
  const [pageSize, setPageSize] = useState(50);
  const [clearAllBeforeRun, setClearAllBeforeRun] = useState(true);

  const progress = useMemo(() => {
    if (!job || job.total_count <= 0) return 0;
    return Math.min(100, Math.floor((job.processed_count / job.total_count) * 100));
  }, [job]);

  const loadLatest = async (tk: string) => {
    const latest = await apiFetch<LatestResp>("/api/v1/import/jobs/latest", {}, tk);
    setJob(latest.job ?? null);
    setRunning(Boolean(latest.runner_running) || latest.job?.status === "running");
    return latest.job;
  };

  const loadItems = async (tk: string, jobId: number) => {
    const params = new URLSearchParams();
    params.set("page", "1");
    params.set("page_size", String(pageSize));
    if (statusFilter) params.set("status", statusFilter);
    const data = await apiFetch<ItemsResp>(`/api/v1/import/jobs/${jobId}/items?${params.toString()}`, {}, tk);
    setItems(data.items ?? []);
  };

  const refresh = async () => {
    if (!isAdmin || !token) return;
    setLoading(true);
    setError("");
    try {
      const latestJob = await loadLatest(token);
      if (latestJob) {
        await loadItems(token, latestJob.id);
      } else {
        setItems([]);
      }
    } catch (e: unknown) {
      setError(String(e));
    } finally {
      setLoading(false);
    }
  };

  const runImport = async () => {
    if (!isAdmin || !token) {
      setError(tx("请先登录管理员账号", "Please sign in with admin account first"));
      return;
    }
    setError("");
    try {
      const body: Record<string, unknown> = {
        mode: runMode,
        workers,
      };
      if (runMode === "luogu") {
        body.clear_all_problems = clearAllBeforeRun;
      } else {
        body.local_pdf_dir = localPdfDir;
        body.target_total = targetTotal;
      }

      await apiFetch<{ started: boolean }>(
        "/api/v1/import/jobs/run",
        {
          method: "POST",
          body: JSON.stringify(body),
        },
        token
      );
      await refresh();
    } catch (e: unknown) {
      setError(String(e));
    }
  };

  const jobOpts = useMemo(() => parseOptions(job?.options_json ?? ""), [job?.options_json]);

  useEffect(() => {
    let canceled = false;
    const init = async () => {
      setCheckingAdmin(true);
      const tk = readToken();
      setToken(tk);
      if (!tk) {
        if (!canceled) {
          setIsAdmin(false);
          setError(tx("请先登录管理员账号", "Please sign in with admin account first"));
          setCheckingAdmin(false);
        }
        return;
      }
      try {
        const me = await apiFetch<MeProfile>("/api/v1/me", {}, tk);
        const allowed = (me?.username ?? "") === "admin";
        if (!canceled) {
          setIsAdmin(allowed);
          if (!allowed) {
            setError(tx("仅管理员可查看平台管理信息", "Platform management is visible to admin only"));
          } else {
            setError("");
          }
        }
      } catch (e: unknown) {
        if (!canceled) {
          setIsAdmin(false);
          setError(String(e));
        }
      } finally {
        if (!canceled) setCheckingAdmin(false);
      }
    };
    void init();
    return () => {
      canceled = true;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (!isAdmin || !token) return;
    void refresh();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isAdmin, token, pageSize, statusFilter]);

  useEffect(() => {
    if (!isAdmin || !token) return;
    const timer = setInterval(() => {
      void refresh();
    }, running ? 3000 : 15000);
    return () => clearInterval(timer);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isAdmin, token, running, pageSize, statusFilter]);

  if (checkingAdmin) {
    return (
      <main className="mx-auto max-w-7xl px-3 py-8 text-sm text-zinc-600">
        {tx("正在校验管理员权限...", "Checking admin access...")}
      </main>
    );
  }

  if (!isAdmin) {
    return (
      <main className="mx-auto max-w-4xl px-3 py-8">
        <h1 className="text-xl font-semibold">{tx("平台管理", "Platform Management")}</h1>
        <p className="mt-3 text-sm text-red-600">
          {error || tx("仅管理员可查看此页面", "This page is available for admin only")}
        </p>
        <div className="mt-4 flex flex-wrap gap-2 text-sm">
          <Link className="rounded border bg-white px-3 py-2 hover:bg-zinc-50" href="/auth">
            {tx("去登录", "Go to Sign In")}
          </Link>
          <Link className="rounded border bg-white px-3 py-2 hover:bg-zinc-50" href="/">
            {tx("返回首页", "Back to Home")}
          </Link>
        </div>
      </main>
    );
  }

  return (
    <main className="mx-auto max-w-7xl px-3 py-6 max-[390px]:px-2 sm:px-4 md:px-6 md:py-8">
      <div className="flex flex-wrap items-center gap-2">
        <h1 className="text-xl font-semibold max-[390px]:text-lg sm:text-2xl flex items-center gap-2">
          <HardDrive size={24} />
          {tx("题库导入/出题任务", "Import / Generation Jobs")}
        </h1>
        <HintTip title={tx("管理说明", "Management Guide")}>
          {tx(
            "该页面仅管理员可用。支持 Luogu 导入与本地 PDF + RAG 出题两种模式，建议先小规模验证再扩大批量。",
            "Admin-only page. Supports Luogu import and Local PDF + RAG generation. Start with a small batch before scaling up."
          )}
        </HintTip>
      </div>

      <section className="mt-4 rounded-xl border bg-white p-4">
        <h2 className="text-base font-medium">{tx("平台管理快捷入口（原 /admin139）", "Platform Shortcuts (moved from /admin139)")}</h2>
        <p className="mt-1 text-xs text-zinc-600">
          {tx(
            "管理员凭据已配置，请使用授权账号登录。",
            "Admin credentials are configured separately. Sign in with an authorized account."
          )}
        </p>
        <div className="mt-3 grid gap-2 sm:grid-cols-2 lg:grid-cols-5">
          <Link className="rounded border bg-zinc-50 px-3 py-2 text-sm hover:bg-zinc-100" href="/auth">
            {tx("登录入口", "Sign In")}
          </Link>
          <Link className="rounded border bg-zinc-50 px-3 py-2 text-sm hover:bg-zinc-100" href="/admin-users">
            {tx("用户积分管理", "User Rating")}
          </Link>
          <Link className="rounded border bg-zinc-50 px-3 py-2 text-sm hover:bg-zinc-100" href="/admin-redeem">
            {tx("积分兑换管理", "Redeem Config")}
          </Link>
          <Link className="rounded border bg-zinc-50 px-3 py-2 text-sm hover:bg-zinc-100" href="/backend-logs">
            {tx("后台日志队列", "Backend Logs")}
          </Link>
          <Link className="rounded border bg-zinc-50 px-3 py-2 text-sm hover:bg-zinc-100" href="/api-docs">
            {tx("API 文档", "API Docs")}
          </Link>
        </div>
      </section>

      <div className="mt-4 rounded-xl border bg-white p-4">
        <div className="flex flex-wrap items-center gap-3">
          <select
            className="w-full rounded border px-2 py-2 text-sm sm:w-auto"
            value={runMode}
            onChange={(e) => setRunMode((e.target.value as "luogu" | "local_pdf_rag") ?? "luogu")}
            disabled={loading || running}
          >
            <option value="luogu">{tx("来源：Luogu CSP J/S", "Source: Luogu CSP J/S")}</option>
            <option value="local_pdf_rag">{tx("来源：本地 PDF + RAG + LLM 出题", "Source: Local PDF + RAG + LLM")}</option>
          </select>
          <label className="flex w-full items-center gap-2 text-sm sm:w-auto">
            {tx("线程", "Workers")}
            <input
              type="number"
              min={1}
              max={16}
              className="w-full rounded border px-2 py-1 sm:w-20"
              value={workers}
              onChange={(e) => setWorkers(Math.max(1, Math.min(16, Number(e.target.value) || 1)))}
              disabled={loading || running}
            />
          </label>
          {runMode === "local_pdf_rag" && (
            <>
              <label className="flex w-full items-center gap-2 text-sm sm:w-auto">
                {tx("PDF目录", "PDF Dir")}
                <input
                  className="w-full rounded border px-2 py-1 sm:w-64"
                  value={localPdfDir}
                  onChange={(e) => setLocalPdfDir(e.target.value)}
                  disabled={loading || running}
                />
              </label>
              <label className="flex w-full items-center gap-2 text-sm sm:w-auto">
                {tx("目标题量", "Target Total")}
                <input
                  type="number"
                  min={1}
                  max={50000}
                  className="w-full rounded border px-2 py-1 sm:w-28"
                  value={targetTotal}
                  onChange={(e) =>
                    setTargetTotal(Math.max(1, Math.min(50000, Number(e.target.value) || 1)))
                  }
                  disabled={loading || running}
                />
              </label>
            </>
          )}
          <button
            className="w-full rounded bg-zinc-900 px-4 py-2 text-white disabled:opacity-50 sm:ml-auto sm:w-auto"
            onClick={() => void runImport()}
            disabled={loading || running}
          >
            {running ? (
              <span className="flex items-center justify-center gap-2">
                <Activity size={16} className="animate-spin" />
                {tx("导入中...", "Importing...")}
              </span>
            ) : (
              <span className="flex items-center justify-center gap-2">
                <Play size={16} />
                {tx("启动导入任务", "Start Import Job")}
              </span>
            )}
          </button>
          {runMode === "luogu" && (
            <label className="flex w-full items-center gap-2 text-sm sm:w-auto">
              <input
                type="checkbox"
                checked={clearAllBeforeRun}
                onChange={(e) => setClearAllBeforeRun(e.target.checked)}
              />
              {tx("启动前清空历史题库", "Clear old problem set before start")}
            </label>
          )}
          <button className="rounded border px-3 py-2 text-sm flex items-center gap-2" onClick={() => void refresh()} disabled={loading}>
            <RefreshCw size={14} className={loading ? "animate-spin" : ""} />
            {tx("刷新", "Refresh")}
          </button>
          <span className={`text-sm flex items-center gap-1 ${running ? "text-emerald-700" : "text-zinc-600"}`}>
            {running ? <Activity size={14} className="animate-pulse" /> : <Server size={14} />}
            {running ? tx("运行中", "Running") : tx("空闲", "Idle")}
          </span>
        </div>
        <div className="mt-2 text-xs text-zinc-500 inline-flex items-center gap-2">
          <span>
            {runMode === "luogu"
              ? tx("当前模式：Luogu 标签导入。", "Mode: Luogu tag import.")
              : tx("当前模式：本地 PDF + RAG 出题。", "Mode: Local PDF + RAG generation.")}
          </span>
          <HintTip title={tx("模式说明", "Mode Notes")} align="left">
            {runMode === "luogu"
              ? tx(
                  "抓取洛谷 CSP-J/CSP-S/NOIP 标签题。可按需选择启动前清空历史题库。",
                  "Fetch Luogu problems tagged CSP-J/CSP-S/NOIP. You can choose to clear historical problem sets before start."
                )
              : tx(
                  "从本地 PDF 提取文本做 RAG，再调用 LLM 生成题目。系统会按目标规模与去重策略补齐题库。",
                  "Extract text from local PDFs for RAG and generate problems with LLM. The system fills the set based on target size and dedupe strategy."
                )}
          </HintTip>
        </div>
      </div>

      {error && <p className="mt-3 text-sm text-red-600">{error}</p>}

      <section className="mt-4 rounded-xl border bg-white p-4">
        <h2 className="text-lg font-medium">{tx("最新任务", "Latest Job")}</h2>
        {!job && <p className="mt-2 text-sm text-zinc-500">{tx("暂无任务记录", "No job records")}</p>}
        {job && (
          <div className="mt-3 space-y-2 text-sm">
            <p>
              {tx("任务", "Job")} #{job.id} · {tx("状态", "Status")}{" "}
              <b className={statusToneClass(job.status)}>{job.status}</b> · {tx("触发方式", "Trigger")} {job.trigger}
            </p>
            <p className="text-zinc-600">
              {tx("模式", "Mode")} {jobOpts?.mode || jobOpts?.source || "luogu"} · {tx("线程", "Workers")} {jobOpts?.workers ?? "-"}
              {typeof jobOpts?.target_total === "number" && ` · ${tx("目标题量", "Target total")} ${jobOpts.target_total}`}
              {(jobOpts?.local_pdf_dir || jobOpts?.pdf_dir) &&
                ` · ${tx("PDF目录", "PDF dir")} ${jobOpts.local_pdf_dir || jobOpts.pdf_dir}`}
            </p>
            <p>
              {tx("总数", "Total")} {job.total_count}，{tx("已处理", "Processed")} {job.processed_count}，{tx("成功", "Success")} {job.success_count}，{tx("失败", "Failed")} {job.failed_count}
            </p>
            <div className="h-2 w-full rounded bg-zinc-100">
              <div className="h-2 rounded bg-emerald-500" style={{ width: `${progress}%` }} />
            </div>
            <p className="text-zinc-600">
              {tx("进度", "Progress")} {progress}% · {tx("开始", "Start")} {fmtTs(job.started_at)} · {tx("结束", "End")} {fmtTs(job.finished_at)}
            </p>
            {job.last_error && <p className="text-red-600">{tx("最近错误：", "Latest error: ")}{job.last_error}</p>}
          </div>
        )}
      </section>

      <section className="mt-4 rounded-xl border bg-white p-4">
        <div className="flex flex-wrap items-center gap-3">
          <h2 className="text-lg font-medium">{tx("任务明细", "Job Items")}</h2>
          <select
            className="rounded border px-2 py-1 text-sm"
            value={statusFilter}
            onChange={(e) => setStatusFilter(e.target.value)}
          >
            <option value="">{tx("全部状态", "All Status")}</option>
            <option value="queued">queued</option>
            <option value="running">running</option>
            <option value="success">success</option>
            <option value="failed">failed</option>
            <option value="skipped">skipped</option>
            <option value="interrupted">interrupted</option>
          </select>
          <select
            className="rounded border px-2 py-1 text-sm"
            value={pageSize}
            onChange={(e) => setPageSize(Number(e.target.value))}
          >
            <option value={50}>{tx("50 条", "50 rows")}</option>
            <option value={100}>{tx("100 条", "100 rows")}</option>
            <option value={200}>{tx("200 条", "200 rows")}</option>
          </select>
        </div>

        <div className="mt-3 rounded-lg border">
          <div className="divide-y md:hidden">
            {items.map((item) => (
              <article key={item.id} className="space-y-1 p-3 text-xs">
                <div className="flex items-center justify-between gap-2">
                  <p className="font-medium">
                    {tx("明细", "Detail")} #{item.id}
                  </p>
                  <span className={statusToneClass(item.status)}>{item.status}</span>
                </div>
                <p className="break-all text-zinc-600">{tx("路径：", "Path: ")}{item.source_path}</p>
                <p className="text-zinc-600">{tx("标题：", "Title: ")}{item.title || "-"}</p>
                <p className="text-zinc-600">
                  {tx("难度：", "Difficulty: ")}{item.difficulty || "-"} · {tx("题目ID：", "Problem ID: ")}{item.problem_id ?? "-"}
                </p>
                {item.error_text && <p className="break-words text-red-600">{tx("错误：", "Error: ")}{item.error_text}</p>}
              </article>
            ))}
            {items.length === 0 && <p className="px-3 py-4 text-center text-sm text-zinc-500">{tx("暂无明细", "No details")}</p>}
          </div>

          <div className="hidden overflow-x-auto md:block">
            <table className="min-w-full text-xs">
              <thead className="bg-zinc-100 text-left">
                <tr>
                  <th className="px-2 py-2">ID</th>
                  <th className="px-2 py-2">{tx("路径", "Path")}</th>
                  <th className="px-2 py-2">{tx("状态", "Status")}</th>
                  <th className="px-2 py-2">{tx("标题", "Title")}</th>
                  <th className="px-2 py-2">{tx("难度", "Difficulty")}</th>
                  <th className="px-2 py-2">{tx("题目ID", "Problem ID")}</th>
                  <th className="px-2 py-2">{tx("错误", "Error")}</th>
                </tr>
              </thead>
              <tbody>
                {items.map((item) => (
                  <tr key={item.id} className="border-t align-top">
                    <td className="px-2 py-2">{item.id}</td>
                    <td className="max-w-[400px] px-2 py-2">
                      <div className="truncate" title={item.source_path}>
                        {item.source_path}
                      </div>
                    </td>
                    <td className={`px-2 py-2 ${statusToneClass(item.status)}`}>{item.status}</td>
                    <td className="max-w-[220px] px-2 py-2">
                      <div className="truncate" title={item.title}>
                        {item.title || "-"}
                      </div>
                    </td>
                    <td className="px-2 py-2">{item.difficulty || "-"}</td>
                    <td className="px-2 py-2">{item.problem_id ?? "-"}</td>
                    <td className="max-w-[320px] px-2 py-2 text-red-600">
                      <div className="truncate" title={item.error_text}>
                        {item.error_text || "-"}
                      </div>
                    </td>
                  </tr>
                ))}
                {items.length === 0 && (
                  <tr>
                    <td className="px-2 py-4 text-center text-zinc-500" colSpan={7}>
                      {tx("暂无明细", "No details")}
                    </td>
                  </tr>
                )}
              </tbody>
            </table>
          </div>
        </div>
      </section>
    </main >
  );
}
