"use client";

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

import { Badge } from "@/components/ui/Badge";
import { apiFetch } from "@/lib/api";
import { cardStyle as cardStyleBase, td, th } from "@/lib/adminStyles";

const cardStyle = { ...cardStyleBase, marginTop: 16 };

// ── Типы ответа GET /api/v1/admin/etl/mapping-review ──────────────────────────
interface MappingReviewRow {
  id: number;
  objective_complex_name: string | null;
  objective_project_id: number | null;
  objective_group: string | null;
  domrf_obj_id: number | null;
  match_method: string | null;
  match_score: number | null;
  is_reviewed: boolean;
  note: string | null;
  created_at: string | null;
  domrf_comm_name: string | null;
  domrf_dev_name: string | null;
  objective_developers: string[];
}

interface MappingReviewResponse {
  rows: MappingReviewRow[];
  total: number;
  limit: number;
  offset: number;
  only_unreviewed: boolean;
}

const LIMIT = 100;

/**
 * Грубая нормализация ЯДРА имени для attention-подсветки (НЕ решение о
 * маппинге — только сигнал глазам). lower + убрать «жк», кавычки/скобки,
 * пунктуацию, схлопнуть пробелы. Если ядро objective НЕ содержится в ядре
 * domrf comm_name (и наоборот) — строка подсвечивается --warn-soft.
 */
function normCore(raw: string | null | undefined): string {
  if (!raw) return "";
  return raw
    .toLowerCase()
    .replace(/[«»"'`“”()［］\[\]]/g, " ")
    .replace(/\bжк\b/g, " ")
    .replace(/\bжилой\s+комплекс\b/g, " ")
    .replace(/[^0-9a-zа-яё]+/gi, " ")
    .replace(/\s+/g, " ")
    .trim();
}

/** true если ядра явно расходятся (ни одно не содержит другое) → внимание. */
function coresMismatch(
  objName: string | null,
  domrfName: string | null,
): boolean {
  const a = normCore(objName);
  const b = normCore(domrfName);
  // Нет одной из сторон для сравнения — не флагаем (нечего сравнивать).
  if (!a || !b) return false;
  if (a === b) return false;
  return !a.includes(b) && !b.includes(a);
}

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

function formatScore(v: number | null): string {
  if (v == null) return "—";
  return v.toFixed(3);
}

export default function MappingReviewPage() {
  const [onlyUnreviewed, setOnlyUnreviewed] = useState(true);
  const [offset, setOffset] = useState(0);
  const [confirmReject, setConfirmReject] = useState<MappingReviewRow | null>(
    null,
  );
  const queryClient = useQueryClient();

  const listKey = ["mapping-review", onlyUnreviewed, offset] as const;

  const list = useQuery({
    queryKey: listKey,
    queryFn: () => {
      const qs = new URLSearchParams({
        only_unreviewed: String(onlyUnreviewed),
        limit: String(LIMIT),
        offset: String(offset),
      });
      return apiFetch<MappingReviewResponse>(
        `/api/v1/admin/etl/mapping-review?${qs.toString()}`,
      );
    },
  });

  const invalidateList = () =>
    queryClient.invalidateQueries({ queryKey: ["mapping-review"] });

  const approve = useMutation({
    mutationFn: (id: number) =>
      apiFetch(`/api/v1/admin/etl/mapping-review/${id}/approve`, {
        method: "POST",
      }),
    onSuccess: () => void invalidateList(),
  });

  const reject = useMutation({
    mutationFn: (id: number) =>
      apiFetch(`/api/v1/admin/etl/mapping-review/${id}/reject`, {
        method: "POST",
      }),
    onSuccess: () => {
      setConfirmReject(null);
      void invalidateList();
    },
  });

  const rows = list.data?.rows ?? [];
  const total = list.data?.total ?? 0;
  const pageFrom = total === 0 ? 0 : offset + 1;
  const pageTo = Math.min(offset + LIMIT, total);
  const canPrev = offset > 0;
  const canNext = offset + LIMIT < total;

  // id строки, по которой сейчас идёт мутация — для локального disabled.
  const pendingApproveId = approve.isPending ? approve.variables : null;
  const pendingRejectId = reject.isPending ? reject.variables : null;

  return (
    <>
      <h2 style={{ marginTop: 0, fontSize: 18 }}>
        Ревью авто-маппингов ЖК → DOM.РФ
      </h2>
      <p style={{ color: "#5b6066", fontSize: 13, marginTop: 4 }}>
        Строки <code>objective_complex_mapping</code>, связавшие
        objective-проект с объектом DOM.РФ автоматически (fuzzy / core-dev /
        geo). Сомнительные — сверху (сорт с бэка). <strong>Подтвердить</strong>{" "}
        помечает маппинг проверенным. <strong>Отклонить</strong> удаляет строку
        — сделки этого комплекса исчезнут из §4.2. Строки, где ядро
        objective-имени не совпадает с ядром DOM.РФ, подсвечены жёлтым для
        внимания (эвристика, не приговор).
      </p>

      {/* Ошибка загрузки списка */}
      {list.isError && (
        <div
          style={{
            marginTop: 16,
            padding: 16,
            background: "#fef2f2",
            border: "1px solid #fecaca",
            borderRadius: 6,
            color: "#991b1b",
            fontSize: 13,
          }}
        >
          Ошибка загрузки списка: {(list.error as Error).message}
        </div>
      )}

      {/* Фильтр + пагинация header */}
      <section style={cardStyle}>
        <div
          style={{
            display: "flex",
            gap: 16,
            alignItems: "center",
            justifyContent: "space-between",
            flexWrap: "wrap",
          }}
        >
          <label
            style={{
              display: "flex",
              alignItems: "center",
              gap: 8,
              fontSize: 13,
              color: "#374151",
              cursor: "pointer",
            }}
          >
            <input
              type="checkbox"
              checked={onlyUnreviewed}
              onChange={(e) => {
                setOnlyUnreviewed(e.target.checked);
                setOffset(0);
              }}
            />
            Только непроверенные
          </label>
          <div
            style={{
              display: "flex",
              alignItems: "center",
              gap: 12,
              fontSize: 13,
              color: "#5b6066",
            }}
          >
            <span>
              {list.isLoading ? (
                "Загрузка…"
              ) : (
                <>
                  {pageFrom}–{pageTo} из{" "}
                  <strong>{total.toLocaleString("ru")}</strong>
                </>
              )}
            </span>
            <button
              type="button"
              onClick={() => setOffset((o) => Math.max(0, o - LIMIT))}
              disabled={!canPrev}
              style={pageBtn(!canPrev)}
              aria-label="Предыдущая страница"
            >
              ←
            </button>
            <button
              type="button"
              onClick={() => setOffset((o) => o + LIMIT)}
              disabled={!canNext}
              style={pageBtn(!canNext)}
              aria-label="Следующая страница"
            >
              →
            </button>
          </div>
        </div>
      </section>

      {/* Ошибка мутаций (inline, не привязана к строке) */}
      {(approve.isError || reject.isError) && (
        <div
          style={{
            marginTop: 16,
            padding: 12,
            background: "#fef2f2",
            border: "1px solid #fecaca",
            borderRadius: 6,
            color: "#991b1b",
            fontSize: 13,
          }}
        >
          {approve.isError &&
            `Не удалось подтвердить: ${(approve.error as Error).message}`}
          {reject.isError &&
            `Не удалось отклонить: ${(reject.error as Error).message}`}
        </div>
      )}

      {/* Таблица */}
      <section style={cardStyle}>
        {!list.isLoading && rows.length === 0 ? (
          <p style={{ color: "#5b6066", fontSize: 13, margin: 0 }}>
            {onlyUnreviewed
              ? "Непроверенных маппингов нет — всё отревьюено."
              : "Маппингов не найдено."}
          </p>
        ) : (
          <div style={{ overflowX: "auto" }}>
            <table
              style={{
                width: "100%",
                borderCollapse: "collapse",
                fontSize: 13,
              }}
            >
              <thead>
                <tr style={{ background: "#f6f7f9" }}>
                  {[
                    "Объектив (ЖК)",
                    "Объектив-девелоперы",
                    "DOM.РФ имя",
                    "DOM.РФ застройщик",
                    "Метод",
                    "Score",
                    "Note",
                    "Дата",
                    "Действия",
                  ].map((h) => (
                    <th key={h} style={th}>
                      {h}
                    </th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {rows.map((r) => {
                  const attention = coresMismatch(
                    r.objective_complex_name,
                    r.domrf_comm_name,
                  );
                  const rowApproving = pendingApproveId === r.id;
                  const rowRejecting = pendingRejectId === r.id;
                  const rowBusy = rowApproving || rowRejecting;
                  return (
                    <tr
                      key={r.id}
                      style={{
                        borderBottom: "1px solid #eef0f3",
                        background: attention ? "var(--warn-soft)" : "#fff",
                      }}
                    >
                      <td style={{ ...td, maxWidth: 260 }}>
                        <span
                          style={{ fontWeight: 500 }}
                          title={r.objective_complex_name ?? ""}
                        >
                          {r.objective_complex_name ?? "—"}
                        </span>
                        {r.objective_group ? (
                          <div style={{ fontSize: 11, color: "#73767e" }}>
                            {r.objective_group}
                          </div>
                        ) : null}
                      </td>
                      <td
                        style={{ ...td, maxWidth: 200, fontSize: 12 }}
                        title={r.objective_developers.join(", ")}
                      >
                        {r.objective_developers.length > 0 ? (
                          <span style={ellipsis}>
                            {r.objective_developers.join(", ")}
                          </span>
                        ) : (
                          <span style={{ color: "#9ca3af" }}>—</span>
                        )}
                      </td>
                      <td
                        style={{ ...td, maxWidth: 280 }}
                        title={r.domrf_comm_name ?? ""}
                      >
                        <span style={ellipsis}>
                          {r.domrf_comm_name ?? (
                            <span style={{ color: "#9ca3af" }}>—</span>
                          )}
                        </span>
                        {r.domrf_obj_id != null ? (
                          <div
                            style={{
                              fontSize: 11,
                              color: "#73767e",
                              fontFamily: "monospace",
                            }}
                          >
                            obj {r.domrf_obj_id}
                          </div>
                        ) : null}
                      </td>
                      <td
                        style={{ ...td, maxWidth: 200, fontSize: 12 }}
                        title={r.domrf_dev_name ?? ""}
                      >
                        <span style={ellipsis}>
                          {r.domrf_dev_name ?? (
                            <span style={{ color: "#9ca3af" }}>—</span>
                          )}
                        </span>
                      </td>
                      <td style={{ ...td, fontSize: 12 }}>
                        <span style={{ fontFamily: "monospace" }}>
                          {r.match_method ?? "—"}
                        </span>
                      </td>
                      <td
                        style={{
                          ...td,
                          fontFamily: "monospace",
                          textAlign: "right",
                          fontVariantNumeric: "tabular-nums",
                        }}
                      >
                        {formatScore(r.match_score)}
                      </td>
                      <td
                        style={{
                          ...td,
                          maxWidth: 160,
                          fontSize: 12,
                          color: "#5b6066",
                        }}
                        title={r.note ?? ""}
                      >
                        <span style={ellipsis}>{r.note ?? "—"}</span>
                      </td>
                      <td style={{ ...td, whiteSpace: "nowrap", fontSize: 12 }}>
                        {formatIso(r.created_at)}
                      </td>
                      <td style={{ ...td, whiteSpace: "nowrap" }}>
                        <div style={{ display: "flex", gap: 6 }}>
                          {r.is_reviewed ? (
                            <Badge variant="success" size="sm">
                              проверен
                            </Badge>
                          ) : (
                            <button
                              type="button"
                              onClick={() => approve.mutate(r.id)}
                              disabled={rowBusy}
                              style={successBtn(rowBusy)}
                            >
                              {rowApproving ? "…" : "Подтвердить"}
                            </button>
                          )}
                          <button
                            type="button"
                            onClick={() => setConfirmReject(r)}
                            disabled={rowBusy}
                            style={dangerBtn(rowBusy)}
                          >
                            {rowRejecting ? "…" : "Отклонить"}
                          </button>
                        </div>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
      </section>

      {/* Confirm-диалог отклонения */}
      {confirmReject && (
        <div
          role="dialog"
          aria-modal="true"
          style={{
            position: "fixed",
            inset: 0,
            background: "rgba(15, 23, 42, 0.45)",
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            zIndex: 1000,
            padding: 16,
          }}
          onClick={() => {
            if (!reject.isPending) setConfirmReject(null);
          }}
        >
          <div
            style={{
              background: "#fff",
              borderRadius: 12,
              padding: 24,
              maxWidth: 460,
              width: "100%",
              boxShadow: "0 10px 40px rgba(0,0,0,0.2)",
            }}
            onClick={(e) => e.stopPropagation()}
          >
            <h3 style={{ margin: "0 0 12px", fontSize: 16, fontWeight: 600 }}>
              Отклонить маппинг?
            </h3>
            <p style={{ margin: "0 0 8px", fontSize: 13, color: "#374151" }}>
              Маппинг будет <strong>удалён</strong> — сделки этого комплекса
              исчезнут из §4.2. Точно?
            </p>
            <p
              style={{
                margin: "0 0 20px",
                fontSize: 12,
                color: "#5b6066",
                background: "#f6f7f9",
                borderRadius: 6,
                padding: "8px 10px",
              }}
            >
              <strong>{confirmReject.objective_complex_name ?? "—"}</strong> →{" "}
              {confirmReject.domrf_comm_name ?? "—"}
            </p>
            {reject.isError && (
              <p style={{ margin: "0 0 12px", fontSize: 12, color: "#b3261e" }}>
                Ошибка: {(reject.error as Error).message}
              </p>
            )}
            <div
              style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}
            >
              <button
                type="button"
                onClick={() => setConfirmReject(null)}
                disabled={reject.isPending}
                style={secondaryBtn(reject.isPending)}
              >
                Отмена
              </button>
              <button
                type="button"
                onClick={() => reject.mutate(confirmReject.id)}
                disabled={reject.isPending}
                style={dangerBtn(reject.isPending)}
              >
                {reject.isPending ? "Удаление…" : "Отклонить и удалить"}
              </button>
            </div>
          </div>
        </div>
      )}
    </>
  );
}

// ── Стили (admin inline-паттерн, см. adminStyles) ─────────────────────────────

const ellipsis: React.CSSProperties = {
  display: "block",
  overflow: "hidden",
  textOverflow: "ellipsis",
  whiteSpace: "nowrap",
};

const pageBtn = (disabled: boolean): React.CSSProperties => ({
  padding: "6px 12px",
  background: "#f3f4f6",
  color: "#1f2937",
  border: "1px solid #d1d5db",
  borderRadius: 6,
  fontSize: 14,
  cursor: disabled ? "not-allowed" : "pointer",
  opacity: disabled ? 0.5 : 1,
});

const successBtn = (disabled: boolean): React.CSSProperties => ({
  padding: "5px 10px",
  background: "#0a7a3a",
  color: "#fff",
  border: "none",
  borderRadius: 6,
  fontSize: 12,
  fontWeight: 600,
  cursor: disabled ? "not-allowed" : "pointer",
  opacity: disabled ? 0.6 : 1,
  whiteSpace: "nowrap",
});

const dangerBtn = (disabled: boolean): React.CSSProperties => ({
  padding: "5px 10px",
  background: "#b3261e",
  color: "#fff",
  border: "none",
  borderRadius: 6,
  fontSize: 12,
  fontWeight: 600,
  cursor: disabled ? "not-allowed" : "pointer",
  opacity: disabled ? 0.6 : 1,
  whiteSpace: "nowrap",
});

const secondaryBtn = (disabled: boolean): React.CSSProperties => ({
  padding: "8px 14px",
  background: "#f3f4f6",
  color: "#1f2937",
  border: "1px solid #d1d5db",
  borderRadius: 6,
  fontSize: 13,
  cursor: disabled ? "not-allowed" : "pointer",
  opacity: disabled ? 0.6 : 1,
});
