"use client";

import { useState } from "react";
import { useQuery } from "@tanstack/react-query";

import { apiFetch } from "@/lib/api";

interface UnifiedRunRow {
  scraper_type: "kn" | "nspd" | "objective" | "nspd_geo";
  run_id: number;
  started_at: string | null;
  finished_at: string | null;
  heartbeat_at: string | null;
  status: string;
  error: string | null;
  triggered_by: string | null;
  scope: string | null;
  requests_count: number | null;
  items_ok: number | null;
  items_failed: number | null;
  sub_items_ok: number | null;
  progress_idx: number | null;
  progress_total: number | null;
  extra: Record<string, unknown> | null;
}

interface UnifiedLogRow {
  scraper_type: "kn" | "nspd" | "nspd_geo";
  log_id: number;
  run_id: number | null;
  ts: string | null;
  level: "debug" | "info" | "warn" | "error";
  stage: string | null;
  entity_id: string | null;
  message: string;
}

const SCRAPER_BADGE: Record<string, { bg: string; fg: string; label: string }> =
  {
    kn: { bg: "#dbeafe", fg: "#1d4ed8", label: "DOM.РФ kn" },
    nspd: { bg: "#fef3c7", fg: "#a16207", label: "NSPD" },
    objective: { bg: "#d1fae5", fg: "#059669", label: "Objective" },
    nspd_geo: { bg: "#ede9fe", fg: "#6d28d9", label: "🗺 NSPD geo" },
  };

const STATUS_COLOR: Record<string, string> = {
  done: "#16a34a",
  running: "#1d4ed8",
  failed: "#b3261e",
  zombie: "#9333ea",
};

function formatIso(s: string | null): string {
  if (!s) return "—";
  return new Date(s).toLocaleString("ru-RU");
}

function diffSecs(a: string | null, b: string | null): string {
  if (!a || !b) return "—";
  const dt = (new Date(b).getTime() - new Date(a).getTime()) / 1000;
  if (dt < 60) return `${dt.toFixed(0)}с`;
  if (dt < 3600) return `${(dt / 60).toFixed(1)} мин`;
  return `${(dt / 3600).toFixed(1)} ч`;
}

export default function ScrapeAllAdminPage() {
  const [token, setToken] = useState<string>(() =>
    typeof window === "undefined"
      ? ""
      : (localStorage.getItem("admin_token") ?? ""),
  );
  const [filter, setFilter] = useState<
    "all" | "kn" | "nspd" | "objective" | "nspd_geo"
  >("all");
  const [logsRunId, setLogsRunId] = useState<number | "">("");

  const saveToken = (v: string) => {
    setToken(v);
    localStorage.setItem("admin_token", v);
  };

  const runs = useQuery({
    queryKey: ["unified-runs", token, filter],
    queryFn: () => {
      const q =
        filter !== "all" ? `?scraper_type=${filter}&limit=30` : "?limit=30";
      return apiFetch<UnifiedRunRow[]>(`/api/v1/admin/scrape/all/runs${q}`, {
        headers: { "X-Admin-Token": token },
      });
    },
    enabled: !!token,
    refetchInterval: 5000,
  });

  const logs = useQuery({
    queryKey: ["unified-logs", token, filter, logsRunId],
    queryFn: () => {
      const params = new URLSearchParams({ limit: "100" });
      if (filter !== "all") params.set("scraper_type", filter);
      if (logsRunId !== "") params.set("run_id", String(logsRunId));
      return apiFetch<UnifiedLogRow[]>(
        `/api/v1/admin/scrape/all/logs?${params}`,
        { headers: { "X-Admin-Token": token } },
      );
    },
    enabled: !!token,
    refetchInterval: 8000,
  });

  // Сводка по statusам
  const summary = (() => {
    const s = { running: 0, done: 0, failed: 0, zombie: 0 } as Record<
      string,
      number
    >;
    runs.data?.forEach((r) => {
      s[r.status] = (s[r.status] ?? 0) + 1;
    });
    return s;
  })();

  return (
    <>
      <h2 style={{ marginTop: 0, fontSize: 18 }}>
        Скраперы — сводный dashboard
      </h2>
      <p style={{ color: "#5b6066", fontSize: 13, marginTop: 4 }}>
        Все скраперы в одной таблице (через <code>v_scrape_runs_unified</code>).
        Для запуска / триггеров — отдельные страницы:{" "}
        <a href="/admin/scrape" style={{ color: "#1d4ed8" }}>
          DOM.РФ kn
        </a>{" "}
        ·{" "}
        <a href="/admin/scrape/geo" style={{ color: "#1d4ed8" }}>
          🗺 NSPD geo
        </a>{" "}
        ·{" "}
        <a href="/admin/scrape/objective" style={{ color: "#1d4ed8" }}>
          Objective
        </a>
        . Старый Playwright-based NSPD-скрапер снят с эксплуатации 2026-05-11 —
        история его прогонов осталась под фильтром <code>nspd</code> только для
        аудита.
      </p>

      <section style={cardStyle}>
        <label style={{ display: "block" }}>
          <span style={labelStyle}>Admin Token</span>
          <input
            type="password"
            value={token}
            onChange={(e) => saveToken(e.target.value)}
            placeholder="SCRAPE_ADMIN_TOKEN"
            style={inputStyle}
          />
        </label>
      </section>

      {/* Сводка-плитки */}
      <section
        style={{
          ...cardStyle,
          marginTop: 16,
          display: "grid",
          gridTemplateColumns: "repeat(4, 1fr)",
          gap: 16,
        }}
      >
        <Stat
          label="🟦 в работе"
          value={summary.running ?? 0}
          color="#1d4ed8"
        />
        <Stat label="✅ успешно" value={summary.done ?? 0} color="#16a34a" />
        <Stat label="❌ failed" value={summary.failed ?? 0} color="#b3261e" />
        <Stat label="🧟 zombie" value={summary.zombie ?? 0} color="#9333ea" />
      </section>

      {/* Фильтр + табы */}
      <section style={{ ...cardStyle, marginTop: 16 }}>
        <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
          <span style={{ ...labelStyle, marginBottom: 0 }}>Filter:</span>
          {(["all", "kn", "nspd", "nspd_geo", "objective"] as const).map(
            (t) => (
              <button
                key={t}
                type="button"
                onClick={() => setFilter(t)}
                style={{
                  ...filterTab,
                  background: filter === t ? "#1d4ed8" : "#f3f4f6",
                  color: filter === t ? "#fff" : "#1f2937",
                }}
              >
                {t === "all" ? "Все" : (SCRAPER_BADGE[t]?.label ?? t)}
              </button>
            ),
          )}
        </div>
      </section>

      {/* Таблица прогонов */}
      <section style={{ ...cardStyle, marginTop: 16 }}>
        <h3 style={sectionTitle}>
          📜 Последние прогоны (top 30, обновляется каждые 5с)
        </h3>
        <div style={{ overflowX: "auto" }}>
          <table style={tableStyle}>
            <thead style={{ background: "#f9fafb" }}>
              <tr>
                <th style={th}>scraper</th>
                <th style={th}>run_id</th>
                <th style={th}>started</th>
                <th style={th}>scope</th>
                <th style={th}>duration</th>
                <th style={{ ...th, textAlign: "right" }}>items_ok</th>
                <th style={{ ...th, textAlign: "right" }}>failed</th>
                <th style={{ ...th, textAlign: "right" }}>sub_ok</th>
                <th style={th}>status</th>
                <th style={th}>trigger</th>
                <th style={th}></th>
              </tr>
            </thead>
            <tbody>
              {runs.data?.map((r) => {
                const heartbeatLag = r.heartbeat_at
                  ? (Date.now() - new Date(r.heartbeat_at).getTime()) / 1000
                  : null;
                const isStale =
                  r.status === "running" &&
                  heartbeatLag !== null &&
                  heartbeatLag > 60;
                const badge = SCRAPER_BADGE[r.scraper_type];
                const statusColor = STATUS_COLOR[r.status] ?? "#6b7280";
                return (
                  <tr
                    key={`${r.scraper_type}-${r.run_id}`}
                    style={{ borderTop: "1px solid #f3f4f6" }}
                  >
                    <td style={td}>
                      {badge && (
                        <span
                          style={{
                            display: "inline-block",
                            padding: "2px 8px",
                            borderRadius: 4,
                            background: badge.bg,
                            color: badge.fg,
                            fontWeight: 500,
                            fontSize: 11,
                          }}
                        >
                          {badge.label}
                        </span>
                      )}
                    </td>
                    <td style={{ ...td, fontFamily: "monospace" }}>
                      {r.run_id}
                    </td>
                    <td style={td}>{formatIso(r.started_at)}</td>
                    <td
                      style={{ ...td, fontFamily: "monospace", fontSize: 11 }}
                    >
                      {r.scope ?? "—"}
                    </td>
                    <td style={td}>
                      {diffSecs(r.started_at, r.finished_at ?? r.heartbeat_at)}
                    </td>
                    <td
                      style={{
                        ...td,
                        textAlign: "right",
                        fontFamily: "monospace",
                      }}
                    >
                      {r.items_ok?.toLocaleString("ru-RU") ?? "—"}
                    </td>
                    <td
                      style={{
                        ...td,
                        textAlign: "right",
                        fontFamily: "monospace",
                        color: r.items_failed ? "#b3261e" : "inherit",
                      }}
                    >
                      {r.items_failed?.toLocaleString("ru-RU") ?? "—"}
                    </td>
                    <td
                      style={{
                        ...td,
                        textAlign: "right",
                        fontFamily: "monospace",
                      }}
                    >
                      {r.sub_items_ok?.toLocaleString("ru-RU") ?? "—"}
                    </td>
                    <td style={td}>
                      <span
                        style={{
                          display: "inline-block",
                          padding: "2px 8px",
                          borderRadius: 4,
                          background: statusColor + "22",
                          color: statusColor,
                          fontWeight: 500,
                        }}
                      >
                        {isStale ? "stale" : r.status}
                      </span>
                    </td>
                    <td style={{ ...td, color: "#6b7280" }}>
                      {r.triggered_by ?? "—"}
                    </td>
                    <td style={td}>
                      {(r.scraper_type === "kn" ||
                        r.scraper_type === "nspd" ||
                        r.scraper_type === "nspd_geo") && (
                        <button
                          type="button"
                          onClick={() => setLogsRunId(r.run_id)}
                          style={{
                            ...secondaryBtn,
                            padding: "4px 10px",
                            fontSize: 11,
                          }}
                        >
                          логи
                        </button>
                      )}
                    </td>
                  </tr>
                );
              })}
              {runs.data?.length === 0 && (
                <tr>
                  <td
                    colSpan={11}
                    style={{
                      ...td,
                      textAlign: "center",
                      color: "#6b7280",
                      padding: 24,
                    }}
                  >
                    Прогонов с фильтром <code>{filter}</code> нет
                  </td>
                </tr>
              )}
            </tbody>
          </table>
        </div>
      </section>

      {/* Logs */}
      <section style={{ ...cardStyle, marginTop: 16 }}>
        <h3 style={sectionTitle}>
          📋 Логи (top 100){" "}
          {logsRunId !== "" && (
            <span style={{ fontSize: 13, fontWeight: 400, color: "#5b6066" }}>
              · фильтр run_id={logsRunId}{" "}
              <button
                type="button"
                onClick={() => setLogsRunId("")}
                style={{
                  background: "none",
                  border: "none",
                  color: "#1d4ed8",
                  cursor: "pointer",
                  fontSize: 13,
                  padding: 0,
                }}
              >
                сбросить
              </button>
            </span>
          )}
        </h3>
        <div style={{ overflowX: "auto", maxHeight: 400, overflowY: "auto" }}>
          <table style={tableStyle}>
            <thead
              style={{ background: "#f9fafb", position: "sticky", top: 0 }}
            >
              <tr>
                <th style={th}>ts</th>
                <th style={th}>scraper</th>
                <th style={th}>run</th>
                <th style={th}>level</th>
                <th style={th}>stage</th>
                <th style={th}>entity</th>
                <th style={th}>message</th>
              </tr>
            </thead>
            <tbody>
              {logs.data?.map((l) => (
                <tr
                  key={`${l.scraper_type}-${l.log_id}`}
                  style={{ borderTop: "1px solid #f3f4f6" }}
                >
                  <td style={{ ...td, fontSize: 11, whiteSpace: "nowrap" }}>
                    {formatIso(l.ts)}
                  </td>
                  <td style={td}>
                    <span
                      style={{
                        fontSize: 10,
                        color: SCRAPER_BADGE[l.scraper_type]?.fg ?? "#6b7280",
                      }}
                    >
                      {l.scraper_type}
                    </span>
                  </td>
                  <td style={{ ...td, fontFamily: "monospace" }}>
                    {l.run_id ?? "—"}
                  </td>
                  <td style={td}>
                    <span
                      style={{
                        color:
                          l.level === "error"
                            ? "#b3261e"
                            : l.level === "warn"
                              ? "#a16207"
                              : "#5b6066",
                        fontSize: 11,
                        fontWeight: 500,
                      }}
                    >
                      {l.level}
                    </span>
                  </td>
                  <td style={{ ...td, fontSize: 11 }}>{l.stage ?? "—"}</td>
                  <td style={{ ...td, fontFamily: "monospace", fontSize: 11 }}>
                    {l.entity_id ?? "—"}
                  </td>
                  <td style={{ ...td, fontSize: 12 }}>{l.message}</td>
                </tr>
              ))}
              {logs.data?.length === 0 && (
                <tr>
                  <td
                    colSpan={7}
                    style={{
                      ...td,
                      textAlign: "center",
                      color: "#6b7280",
                      padding: 24,
                    }}
                  >
                    Логов нет (objective пока не пишет в log — только runs)
                  </td>
                </tr>
              )}
            </tbody>
          </table>
        </div>
      </section>
    </>
  );
}

function Stat({
  label,
  value,
  color,
}: {
  label: string;
  value: number;
  color: string;
}) {
  return (
    <div>
      <div style={{ fontSize: 12, color: "#5b6066", marginBottom: 4 }}>
        {label}
      </div>
      <div
        style={{
          fontFamily: "monospace",
          fontSize: 28,
          fontWeight: 600,
          color,
        }}
      >
        {value}
      </div>
    </div>
  );
}

const cardStyle = {
  background: "#fff",
  border: "1px solid #e6e8ec",
  borderRadius: 12,
  padding: 20,
};
const sectionTitle = {
  margin: "0 0 12px",
  fontSize: 16,
  fontWeight: 600 as const,
};
const labelStyle = {
  display: "block",
  fontSize: 12,
  color: "#5b6066",
  marginBottom: 4,
  textTransform: "uppercase" as const,
  letterSpacing: 0.4,
};
const inputStyle = {
  padding: "8px 10px",
  border: "1px solid #d1d5db",
  borderRadius: 6,
  fontSize: 14,
  width: "100%",
  boxSizing: "border-box" as const,
};
const filterTab = {
  padding: "6px 14px",
  border: "none",
  borderRadius: 6,
  fontSize: 13,
  fontWeight: 500 as const,
  cursor: "pointer",
};
const secondaryBtn = {
  padding: "8px 14px",
  background: "#f3f4f6",
  color: "#1f2937",
  border: "1px solid #d1d5db",
  borderRadius: 6,
  fontSize: 13,
  cursor: "pointer",
};
const tableStyle = {
  width: "100%",
  borderCollapse: "collapse" as const,
  fontSize: 12,
};
const th = {
  padding: "8px 10px",
  textAlign: "left" as const,
  fontWeight: 600 as const,
  borderBottom: "1px solid #e6e8ec",
};
const td = { padding: "8px 10px" };
