"use client";

import { Fragment, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";

import { apiFetch } from "@/lib/api";
import { cardStyle, inputStyle, labelStyle, td, th } from "@/lib/adminStyles";

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

interface PhaseState {
  phase?: string;
  parcels_meta?: number;
  parcels_fetched?: number;
  buildings_meta?: number;
  buildings_fetched?: number;
  retries?: number;
}

interface CadastreJob {
  job_id: number;
  name: string | null;
  job_kind: string;
  scope: string;
  status:
    | "queued"
    | "running"
    | "done"
    | "failed"
    | "zombie"
    | "cancelled"
    | "paused";
  triggered_by: string | null;
  rate_ms: number;
  created_at: string | null;
  started_at: string | null;
  finished_at: string | null;
  heartbeat_at: string | null;
  targets_total: number;
  targets_done: number;
  targets_failed: number;
  targets_skipped: number;
  requests_count: number;
  waf_blocked_count: number;
  error: string | null;
  phase_state: PhaseState | null;
  progress_pct?: number;
}

interface CreateCadastreJobRequest {
  scope: "pilot" | "ekb_full" | "manual_list";
  name?: string;
  quarters?: string[];
  limit?: number;
}

interface CreateCadastreJobResponse {
  job_id: number;
  scope: string;
  targets_total: number;
  estimate_minutes: number;
}

type ScopeOption = "pilot" | "ekb_full" | "manual_list";

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------

const STATUS_COLOR: Record<string, string> = {
  queued: "#6b7280",
  running: "#1d4ed8",
  done: "#16a34a",
  failed: "#b3261e",
  zombie: "#dc2626",
  cancelled: "#9333ea",
  paused: "#a16207",
};

const SCOPE_LABEL: Record<ScopeOption, string> = {
  pilot: "Pilot (50 кварталов ЕКБ)",
  ekb_full: "Full ЕКБ (2 408 кварталов)",
  manual_list: "Manual list",
};

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

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)} ч`;
}

function calcProgress(job: CadastreJob): number {
  if (job.progress_pct !== undefined) return job.progress_pct;
  if (job.targets_total === 0) return 0;
  return (job.targets_done / job.targets_total) * 100;
}

function reqPerSec(job: CadastreJob): string {
  if (!job.started_at || job.requests_count === 0) return "—";
  const endTs = job.heartbeat_at ?? job.finished_at;
  if (!endTs) return "—";
  const elapsed =
    (new Date(endTs).getTime() - new Date(job.started_at).getTime()) / 1000;
  if (elapsed <= 0) return "—";
  return (job.requests_count / elapsed).toFixed(2);
}

// ---------------------------------------------------------------------------
// Query keys
// ---------------------------------------------------------------------------

const jobsKey = () => ["admin", "cadastre", "jobs"];
const jobKey = (id: number) => ["admin", "cadastre", "job", id];

// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------

export default function CadastreScrapeAdminPage() {
  const [scope, setScope] = useState<ScopeOption>("pilot");
  const [name, setName] = useState("");
  const [quartersText, setQuartersText] = useState("");
  const [limit, setLimit] = useState<string>("");
  const [lastResp, setLastResp] = useState<CreateCadastreJobResponse | null>(
    null,
  );
  const [expandedId, setExpandedId] = useState<number | null>(null);

  const queryClient = useQueryClient();

  // -------------------------------------------------------------------------
  // Queries
  // -------------------------------------------------------------------------

  const jobs = useQuery({
    queryKey: jobsKey(),
    queryFn: () =>
      apiFetch<CadastreJob[]>("/api/v1/admin/cadastre/jobs?limit=30"),
    refetchInterval: 5000,
  });

  // Per-job detail (only fetched when row is expanded)
  const expandedJob = useQuery({
    queryKey: jobKey(expandedId ?? 0),
    queryFn: () =>
      apiFetch<CadastreJob>(`/api/v1/admin/cadastre/jobs/${expandedId}`),
    enabled: expandedId !== null,
    refetchInterval: expandedId !== null ? 5000 : false,
  });

  // -------------------------------------------------------------------------
  // Mutations
  // -------------------------------------------------------------------------

  const createJob = useMutation({
    mutationFn: () => {
      const body: CreateCadastreJobRequest = { scope };
      if (name.trim()) body.name = name.trim();
      if (scope === "manual_list") {
        body.quarters = quartersText
          .split(/[\n,]+/)
          .map((s) => s.trim())
          .filter(Boolean);
      }
      const limitNum = parseInt(limit, 10);
      if (!isNaN(limitNum) && limitNum > 0) body.limit = limitNum;
      return apiFetch<CreateCadastreJobResponse>(
        "/api/v1/admin/cadastre/jobs",
        {
          method: "POST",
          body: JSON.stringify(body),
        },
      );
    },
    onSuccess: (data) => {
      setLastResp(data);
      void queryClient.invalidateQueries({ queryKey: jobsKey() });
    },
  });

  const cancelJob = useMutation({
    mutationFn: (id: number) =>
      apiFetch<{ cancelled: boolean }>(
        `/api/v1/admin/cadastre/jobs/${id}/cancel`,
        { method: "POST" },
      ),
    onSuccess: (_data, id) => {
      void queryClient.invalidateQueries({ queryKey: jobKey(id) });
      void queryClient.invalidateQueries({ queryKey: jobsKey() });
    },
  });

  const resumeJob = useMutation({
    mutationFn: (id: number) =>
      apiFetch<{ resumed: boolean }>(
        `/api/v1/admin/cadastre/jobs/${id}/resume`,
        { method: "POST" },
      ),
    onSuccess: (_data, id) => {
      void queryClient.invalidateQueries({ queryKey: jobKey(id) });
      void queryClient.invalidateQueries({ queryKey: jobsKey() });
    },
  });

  // -------------------------------------------------------------------------
  // Handlers
  // -------------------------------------------------------------------------

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (scope === "manual_list" && !quartersText.trim()) {
      alert("Для Manual list укажите хотя бы один квартал");
      return;
    }
    createJob.mutate();
  };

  const toggleExpand = (id: number) => {
    setExpandedId((prev) => (prev === id ? null : id));
  };

  // -------------------------------------------------------------------------
  // Render helpers
  // -------------------------------------------------------------------------

  const renderProgressBar = (job: CadastreJob) => {
    const pct = calcProgress(job);
    const color = STATUS_COLOR[job.status] ?? "#6b7280";
    return (
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          gap: 2,
          alignItems: "flex-end",
        }}
      >
        <strong>{pct.toFixed(1)}%</strong>
        <div
          style={{
            width: 80,
            height: 6,
            background: "#e5e7eb",
            borderRadius: 3,
            overflow: "hidden",
          }}
        >
          <div
            style={{
              width: `${Math.min(pct, 100)}%`,
              height: "100%",
              background: color,
            }}
          />
        </div>
      </div>
    );
  };

  const renderHeartbeat = (job: CadastreJob) => {
    if (!job.heartbeat_at) return <span style={{ color: "#9ca3af" }}>—</span>;
    const lagMs = Date.now() - new Date(job.heartbeat_at).getTime();
    const lagMin = lagMs / 60000;
    const stale = job.status === "running" && lagMin > 10;
    const lagStr =
      lagMs < 60000
        ? `${Math.round(lagMs / 1000)} с`
        : `${lagMin.toFixed(1)} мин`;
    return (
      <span style={{ color: stale ? "#dc2626" : "inherit", fontSize: 11 }}>
        {stale ? `STALE (${lagStr})` : lagStr}
      </span>
    );
  };

  const renderStatusBadge = (job: CadastreJob) => {
    const color = STATUS_COLOR[job.status] ?? "#6b7280";
    const heartbeatLag = job.heartbeat_at
      ? (Date.now() - new Date(job.heartbeat_at).getTime()) / 60000
      : null;
    const isZombie =
      job.status === "running" && heartbeatLag !== null && heartbeatLag > 10;
    return (
      <span
        style={{
          display: "inline-block",
          padding: "2px 8px",
          borderRadius: 4,
          background: color + "22",
          color,
          fontWeight: 500,
        }}
      >
        {isZombie ? "zombie" : job.status}
      </span>
    );
  };

  const renderActions = (job: CadastreJob) => (
    <div style={{ display: "flex", gap: 4 }}>
      {(job.status === "running" || job.status === "queued") && (
        <button
          type="button"
          onClick={() => cancelJob.mutate(job.job_id)}
          disabled={cancelJob.isPending}
          style={{ ...secondaryBtn, padding: "4px 8px", fontSize: 11 }}
        >
          Cancel
        </button>
      )}
      {(job.status === "failed" ||
        job.status === "cancelled" ||
        job.status === "paused") &&
        job.phase_state?.phase !== "done" && (
          <button
            type="button"
            onClick={() => resumeJob.mutate(job.job_id)}
            disabled={resumeJob.isPending}
            style={{
              ...secondaryBtn,
              padding: "4px 8px",
              fontSize: 11,
              background: "#dbeafe",
              color: "#1d4ed8",
            }}
          >
            Resume
          </button>
        )}
    </div>
  );

  const renderExpandedPanel = (job: CadastreJob | undefined) => {
    if (!job) {
      return (
        <tr>
          <td
            colSpan={10}
            style={{
              ...td,
              background: "#f9fafb",
              fontSize: 12,
              color: "#5b6066",
            }}
          >
            Загрузка деталей...
          </td>
        </tr>
      );
    }
    return (
      <tr>
        <td
          colSpan={10}
          style={{
            ...td,
            background: "#f9fafb",
            borderBottom: "2px solid #e6e8ec",
          }}
        >
          <div
            style={{
              display: "grid",
              gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
              gap: 16,
              fontSize: 13,
            }}
          >
            {/* Phase state */}
            <div>
              <div
                style={{
                  fontWeight: 600,
                  marginBottom: 6,
                  fontSize: 12,
                  color: "#5b6066",
                }}
              >
                PHASE STATE
              </div>
              {job.phase_state ? (
                <pre
                  style={{
                    margin: 0,
                    fontFamily: "monospace",
                    fontSize: 11,
                    background: "#1e293b",
                    color: "#e2e8f0",
                    padding: "8px 10px",
                    borderRadius: 6,
                    overflowX: "auto",
                  }}
                >
                  {JSON.stringify(job.phase_state, null, 2)}
                </pre>
              ) : (
                <span style={{ color: "#9ca3af", fontSize: 12 }}>—</span>
              )}
            </div>

            {/* Stats */}
            <div>
              <div
                style={{
                  fontWeight: 600,
                  marginBottom: 6,
                  fontSize: 12,
                  color: "#5b6066",
                }}
              >
                СТАТИСТИКА
              </div>
              <table style={{ fontSize: 12, borderCollapse: "collapse" }}>
                <tbody>
                  <tr>
                    <td
                      style={{
                        ...td,
                        padding: "3px 12px 3px 0",
                        color: "#5b6066",
                      }}
                    >
                      Запросов
                    </td>
                    <td
                      style={{
                        ...td,
                        padding: "3px 0",
                        fontFamily: "monospace",
                      }}
                    >
                      {job.requests_count.toLocaleString("ru-RU")}
                    </td>
                  </tr>
                  <tr>
                    <td
                      style={{
                        ...td,
                        padding: "3px 12px 3px 0",
                        color: "#5b6066",
                      }}
                    >
                      Req/s
                    </td>
                    <td
                      style={{
                        ...td,
                        padding: "3px 0",
                        fontFamily: "monospace",
                      }}
                    >
                      {reqPerSec(job)}
                    </td>
                  </tr>
                  <tr>
                    <td
                      style={{
                        ...td,
                        padding: "3px 12px 3px 0",
                        color: "#5b6066",
                      }}
                    >
                      WAF blocked
                    </td>
                    <td
                      style={{
                        ...td,
                        padding: "3px 0",
                        fontFamily: "monospace",
                        color:
                          job.waf_blocked_count > 5 ? "#dc2626" : "inherit",
                        fontWeight: job.waf_blocked_count > 5 ? 700 : 400,
                      }}
                    >
                      {job.waf_blocked_count}
                      {job.waf_blocked_count > 5 && " ⚠ HIGH"}
                    </td>
                  </tr>
                  <tr>
                    <td
                      style={{
                        ...td,
                        padding: "3px 12px 3px 0",
                        color: "#5b6066",
                      }}
                    >
                      Skipped
                    </td>
                    <td
                      style={{
                        ...td,
                        padding: "3px 0",
                        fontFamily: "monospace",
                      }}
                    >
                      {job.targets_skipped}
                    </td>
                  </tr>
                  <tr>
                    <td
                      style={{
                        ...td,
                        padding: "3px 12px 3px 0",
                        color: "#5b6066",
                      }}
                    >
                      Rate ms
                    </td>
                    <td
                      style={{
                        ...td,
                        padding: "3px 0",
                        fontFamily: "monospace",
                      }}
                    >
                      {job.rate_ms}
                    </td>
                  </tr>
                  <tr>
                    <td
                      style={{
                        ...td,
                        padding: "3px 12px 3px 0",
                        color: "#5b6066",
                      }}
                    >
                      Started
                    </td>
                    <td style={{ ...td, padding: "3px 0", fontSize: 11 }}>
                      {formatIso(job.started_at)}
                    </td>
                  </tr>
                  <tr>
                    <td
                      style={{
                        ...td,
                        padding: "3px 12px 3px 0",
                        color: "#5b6066",
                      }}
                    >
                      Finished
                    </td>
                    <td style={{ ...td, padding: "3px 0", fontSize: 11 }}>
                      {formatIso(job.finished_at)}
                    </td>
                  </tr>
                  <tr>
                    <td
                      style={{
                        ...td,
                        padding: "3px 12px 3px 0",
                        color: "#5b6066",
                      }}
                    >
                      Triggered by
                    </td>
                    <td
                      style={{
                        ...td,
                        padding: "3px 0",
                        fontFamily: "monospace",
                      }}
                    >
                      {job.triggered_by ?? "—"}
                    </td>
                  </tr>
                </tbody>
              </table>
            </div>

            {/* Error */}
            {job.error && (
              <div>
                <div
                  style={{
                    fontWeight: 600,
                    marginBottom: 6,
                    fontSize: 12,
                    color: "#dc2626",
                  }}
                >
                  ERROR
                </div>
                <pre
                  style={{
                    margin: 0,
                    fontFamily: "monospace",
                    fontSize: 11,
                    background: "#fef2f2",
                    color: "#991b1b",
                    padding: "8px 10px",
                    borderRadius: 6,
                    overflowX: "auto",
                    whiteSpace: "pre-wrap",
                    wordBreak: "break-all",
                  }}
                >
                  {job.error}
                </pre>
              </div>
            )}
          </div>
        </td>
      </tr>
    );
  };

  // -------------------------------------------------------------------------
  // Render
  // -------------------------------------------------------------------------

  return (
    <>
      <h2 style={{ marginTop: 0, fontSize: 18 }}>
        Cadastre bulk harvest — ручной запуск
      </h2>
      <p style={{ color: "#5b6066", fontSize: 13, marginTop: 4 }}>
        Bulk-загрузка кадастровых данных (участки + здания) из NSPD. State
        хранится в БД (<code>cadastre_jobs</code> +{" "}
        <code>cadastre_targets</code>) — при redeploy job продолжается с
        незавершённых targets.
      </p>

      {/* Create job form */}
      <section style={cardStyle}>
        <h3 style={sectionTitle}>Запуск bulk harvest</h3>
        <form onSubmit={handleSubmit}>
          <div style={{ display: "grid", gap: 12 }}>
            <label>
              <span style={labelStyle}>Имя задачи (опционально)</span>
              <input
                type="text"
                value={name}
                onChange={(e) => setName(e.target.value)}
                placeholder={`pilot_${new Date().toISOString().slice(0, 10)}`}
                style={inputStyle}
              />
            </label>

            {/* Scope radio buttons */}
            <div>
              <span style={labelStyle}>Scope</span>
              <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
                {(["pilot", "ekb_full", "manual_list"] as ScopeOption[]).map(
                  (s) => (
                    <label
                      key={s}
                      style={{
                        display: "flex",
                        alignItems: "center",
                        gap: 8,
                        fontSize: 14,
                        cursor: "pointer",
                      }}
                    >
                      <input
                        type="radio"
                        name="scope"
                        value={s}
                        checked={scope === s}
                        onChange={() => setScope(s)}
                      />
                      {SCOPE_LABEL[s]}
                    </label>
                  ),
                )}
              </div>
            </div>

            {/* Manual quarters textarea */}
            {scope === "manual_list" && (
              <label>
                <span style={labelStyle}>
                  Кварталы (по одному на строку или через запятую)
                </span>
                <textarea
                  value={quartersText}
                  onChange={(e) => setQuartersText(e.target.value)}
                  placeholder={"66:41:0303161\n66:41:0204016"}
                  rows={6}
                  style={{
                    ...inputStyle,
                    fontFamily: "monospace",
                    fontSize: 12,
                  }}
                />
              </label>
            )}

            {/* Optional limit */}
            <label style={{ maxWidth: 200 }}>
              <span style={labelStyle}>
                Limit (опц., для pilot — default 50)
              </span>
              <input
                type="number"
                min={1}
                value={limit}
                onChange={(e) => setLimit(e.target.value)}
                placeholder="50"
                style={inputStyle}
              />
            </label>

            <div style={{ display: "flex", gap: 12, alignItems: "center" }}>
              <button
                type="submit"
                disabled={createJob.isPending}
                style={primaryBtn}
              >
                {createJob.isPending ? "Создание…" : "Запустить"}
              </button>
              {lastResp && (
                <span style={{ fontSize: 13, color: "#5b6066" }}>
                  Job <code>#{lastResp.job_id}</code> создан, targets:{" "}
                  <strong>
                    {lastResp.targets_total.toLocaleString("ru-RU")}
                  </strong>
                  , примерно <strong>{lastResp.estimate_minutes}</strong> мин
                </span>
              )}
              {createJob.isError && (
                <span style={{ color: "#b3261e", fontSize: 13 }}>
                  {(createJob.error as Error).message}
                </span>
              )}
            </div>
          </div>
        </form>
      </section>

      {/* Jobs table */}
      <section style={{ ...cardStyle, marginTop: 16 }}>
        <h3 style={sectionTitle}>Cadastre jobs (top 30, refresh 5 с)</h3>
        {jobs.isLoading ? (
          <p style={{ color: "#5b6066" }}>Загрузка…</p>
        ) : jobs.isError ? (
          <p style={{ color: "#b3261e" }}>
            Ошибка: {(jobs.error as Error).message}
          </p>
        ) : (
          <div style={{ overflowX: "auto" }}>
            <table style={tableStyle}>
              <thead style={{ background: "#f9fafb" }}>
                <tr>
                  <th style={th}>ID</th>
                  <th style={th}>Имя</th>
                  <th style={th}>Scope</th>
                  <th style={th}>Статус</th>
                  <th style={{ ...th, textAlign: "right" }}>Progress</th>
                  <th style={{ ...th, textAlign: "right" }}>Targets</th>
                  <th style={{ ...th, textAlign: "right" }}>Errors</th>
                  <th style={{ ...th, textAlign: "right" }}>WAF</th>
                  <th style={th}>Started</th>
                  <th style={th}>Heartbeat</th>
                  <th style={th}></th>
                </tr>
              </thead>
              <tbody>
                {jobs.data?.map((job) => (
                  <Fragment key={job.job_id}>
                    <tr
                      style={{
                        borderTop: "1px solid #f3f4f6",
                        cursor: "pointer",
                        background:
                          expandedId === job.job_id ? "#f0f7ff" : undefined,
                      }}
                      onClick={() => toggleExpand(job.job_id)}
                    >
                      <td style={{ ...td, fontFamily: "monospace" }}>
                        {job.job_id}
                      </td>
                      <td
                        style={{
                          ...td,
                          maxWidth: 180,
                          overflow: "hidden",
                          textOverflow: "ellipsis",
                          whiteSpace: "nowrap",
                        }}
                      >
                        {job.name ?? <em style={{ color: "#9ca3af" }}>—</em>}
                      </td>
                      <td style={{ ...td, fontSize: 11 }}>{job.scope}</td>
                      <td style={td}>{renderStatusBadge(job)}</td>
                      <td style={{ ...td, textAlign: "right" }}>
                        {renderProgressBar(job)}
                      </td>
                      <td
                        style={{
                          ...td,
                          textAlign: "right",
                          fontFamily: "monospace",
                          fontSize: 11,
                        }}
                      >
                        {job.targets_done.toLocaleString("ru-RU")}/
                        {job.targets_total.toLocaleString("ru-RU")}
                        {job.targets_failed > 0 && (
                          <span style={{ color: "#b3261e" }}>
                            {" "}
                            ({job.targets_failed} fail)
                          </span>
                        )}
                      </td>
                      <td
                        style={{
                          ...td,
                          textAlign: "right",
                          fontFamily: "monospace",
                          color: job.targets_failed > 0 ? "#b3261e" : "inherit",
                        }}
                      >
                        {job.targets_failed || "—"}
                      </td>
                      <td
                        style={{
                          ...td,
                          textAlign: "right",
                          fontFamily: "monospace",
                          color:
                            job.waf_blocked_count > 5
                              ? "#dc2626"
                              : job.waf_blocked_count > 0
                                ? "#a16207"
                                : "inherit",
                          fontWeight: job.waf_blocked_count > 5 ? 700 : 400,
                        }}
                      >
                        {job.waf_blocked_count || "—"}
                        {job.waf_blocked_count > 5 && " ⚠"}
                      </td>
                      <td style={{ ...td, fontSize: 11 }}>
                        {formatIso(job.started_at)}
                      </td>
                      <td style={td}>{renderHeartbeat(job)}</td>
                      <td style={td} onClick={(e) => e.stopPropagation()}>
                        {renderActions(job)}
                      </td>
                    </tr>
                    {expandedId === job.job_id &&
                      renderExpandedPanel(
                        expandedJob.data?.job_id === job.job_id
                          ? expandedJob.data
                          : undefined,
                      )}
                  </Fragment>
                ))}
                {(jobs.data?.length ?? 0) === 0 && (
                  <tr>
                    <td
                      colSpan={11}
                      style={{
                        ...td,
                        textAlign: "center",
                        color: "#6b7280",
                        padding: 24,
                      }}
                    >
                      Cadastre-jobs ещё не было
                    </td>
                  </tr>
                )}
              </tbody>
            </table>
          </div>
        )}
      </section>
    </>
  );
}

// ---------------------------------------------------------------------------
// Local styles
// ---------------------------------------------------------------------------

const sectionTitle: React.CSSProperties = {
  margin: "0 0 12px",
  fontSize: 16,
  fontWeight: 600,
};

const primaryBtn: React.CSSProperties = {
  padding: "10px 18px",
  background: "#1d4ed8",
  color: "#fff",
  border: "none",
  borderRadius: 6,
  fontSize: 14,
  fontWeight: 600,
  cursor: "pointer",
};

const secondaryBtn: React.CSSProperties = {
  padding: "8px 14px",
  background: "#f3f4f6",
  color: "#1f2937",
  border: "1px solid #d1d5db",
  borderRadius: 6,
  fontSize: 13,
  cursor: "pointer",
};

const tableStyle: React.CSSProperties = {
  width: "100%",
  borderCollapse: "collapse",
  fontSize: 12,
};
