"use client";

/**
 * ZouitLayer — #255 (по требованию Макса): ЗОУИТ (зоны с особыми условиями
 * использования территории) схематичными полигонами поверх карты Site Finder.
 *
 * Раньше пересечения были только текстовым списком под картой
 * (NspdZouitOverlapsBlock). Этот слой рисует реальную геометрию охранных зон,
 * чтобы видно было ГДЕ зона относительно участка.
 *
 * Геометрия приходит из /analyze payload: каждый NspdZouitOverlap.geom_geojson —
 * строка GeoJSON (ST_AsGeoJSON(geom::geometry) на backend, EPSG:4326,
 * Polygon/MultiPolygon). Парсим через JSON.parse → <GeoJSON> (react-leaflet).
 *
 * Цвета — token-hex (документированное исключение карты/чартов, ui-tokens.md):
 *   blocker → --danger   (#b3261e) — охранные зоны трубопровода / электр. / газа
 *   warning → --accent-2 (#f2994a) — СЗЗ, охранная зона тепловой сети
 *   info    → --viz-2    (#0ea5e9) — зоны публичного сервитута и прочее
 *
 * Severity выводим из type_zone / category_name / name (keyword-match), т.к.
 * cad_zouit fallback кладёт человекочитаемый тип в type_zone, а nspd-dump path —
 * в name. Видимость per-severity управляется из SiteMap (как MarketLayers).
 *
 * Graceful: overlap без geom_geojson / с невалидным JSON / без полигональной
 * геометрии просто пропускается (текстовый список остаётся источником истины).
 */

import { GeoJSON, LayerGroup, Popup } from "react-leaflet";
import type { Feature, Geometry } from "geojson";

import type { NspdZouitOverlap } from "@/types/nspd";

// ---------------------------------------------------------------------------
// Severity classification
// ---------------------------------------------------------------------------

export type ZouitSeverity = "blocker" | "warning" | "info";

export interface ZouitSeverityStyle {
  color: string;
  label: string;
}

// token-hex (map/chart exception per ui-tokens.md)
export const ZOUIT_SEVERITY_STYLES: Record<ZouitSeverity, ZouitSeverityStyle> =
  {
    blocker: { color: "#b3261e", label: "Блокирующие" }, // --danger
    warning: { color: "#f2994a", label: "Ограничивающие" }, // --accent-2
    info: { color: "#0ea5e9", label: "Информационные" }, // --viz-2
  };

// Порядок отрисовки / легенды: blocker сверху (важнее), info снизу.
export const ZOUIT_ALL_SEVERITIES: ZouitSeverity[] = [
  "blocker",
  "warning",
  "info",
];

// Keyword-правила (проверяются по порядку; первый матч выигрывает). Сначала
// blocker (опасные инженерные зоны), затем warning (СЗЗ/тепло). Без матча → info.
const SEVERITY_KEYWORDS: Array<{ sev: ZouitSeverity; keywords: string[] }> = [
  {
    sev: "blocker",
    keywords: [
      "трубопровод",
      "электр",
      "газопровод",
      "газораспредел",
      "линий электропередач",
      "нефтепровод",
      "магистральн",
      "взрывоопасн",
      "опасн",
    ],
  },
  {
    sev: "warning",
    keywords: [
      "санитарно-защитн",
      "сзз",
      "тепловой сети",
      "теплосет",
      "охранная зона связи",
      "охранная зона",
    ],
  },
];

/**
 * Классифицирует ЗОУИТ по severity. Источник текста: type_zone (cad_zouit
 * fallback) → category_name → name (nspd-dump path). Без совпадений → "info"
 * (зоны сервитута и прочее — наименее ограничивающие).
 */
export function classifyZouit(overlap: NspdZouitOverlap): ZouitSeverity {
  const haystack = [overlap.type_zone, overlap.category_name, overlap.name]
    .filter((s): s is string => typeof s === "string" && s.length > 0)
    .join(" ")
    .toLowerCase();

  for (const { sev, keywords } of SEVERITY_KEYWORDS) {
    if (keywords.some((kw) => haystack.includes(kw))) return sev;
  }
  return "info";
}

// ---------------------------------------------------------------------------
// Geometry parsing
// ---------------------------------------------------------------------------

// Какие типы геометрии этот слой умеет рисовать как заливку.
const POLYGON_TYPES = new Set<Geometry["type"]>(["Polygon", "MultiPolygon"]);

/**
 * Парсит geom_geojson (строка) → Geometry. Возвращает null для отсутствующего /
 * невалидного / неполигонального ввода — фича тогда просто не рисуется (graceful).
 * Backend отдаёт строку через ST_AsGeoJSON; терпим и уже-распарсенный объект на
 * случай будущей смены контракта.
 */
export function parseZouitGeometry(
  raw: string | null | undefined,
): Geometry | null {
  if (raw === null || raw === undefined) return null;

  let parsed: unknown;
  if (typeof raw === "string") {
    if (raw.length === 0) return null;
    try {
      parsed = JSON.parse(raw);
    } catch {
      return null;
    }
  } else {
    parsed = raw;
  }

  if (typeof parsed !== "object" || parsed === null) return null;
  const candidate = parsed as { type?: unknown; coordinates?: unknown };
  if (
    typeof candidate.type !== "string" ||
    !POLYGON_TYPES.has(candidate.type as Geometry["type"]) ||
    !Array.isArray(candidate.coordinates)
  ) {
    return null;
  }
  return parsed as Geometry;
}

// ---------------------------------------------------------------------------
// Grouping helper (exported so SiteMap can build per-severity counts)
// ---------------------------------------------------------------------------

export interface ZouitMappable {
  overlap: NspdZouitOverlap;
  geometry: Geometry;
  severity: ZouitSeverity;
}

/**
 * Из сырых overlaps оставляет только рисуемые (валидная полигональная геометрия)
 * и группирует по severity. Используется и слоем, и панелью-тумблером (счётчики
 * должны отражать именно рисуемые объекты, а не все overlaps).
 */
export function groupZouitBySeverity(
  overlaps: NspdZouitOverlap[],
): Map<ZouitSeverity, ZouitMappable[]> {
  const grouped = new Map<ZouitSeverity, ZouitMappable[]>();
  for (const sev of ZOUIT_ALL_SEVERITIES) grouped.set(sev, []);

  for (const overlap of overlaps) {
    const geometry = parseZouitGeometry(overlap.geom_geojson);
    if (!geometry) continue;
    const severity = classifyZouit(overlap);
    grouped.get(severity)!.push({ overlap, geometry, severity });
  }
  return grouped;
}

// ---------------------------------------------------------------------------
// Map layer
// ---------------------------------------------------------------------------

interface LayerProps {
  grouped: Map<ZouitSeverity, ZouitMappable[]>;
  visibleSeverities: Set<ZouitSeverity>;
}

export function ZouitLayer({ grouped, visibleSeverities }: LayerProps) {
  return (
    <>
      {ZOUIT_ALL_SEVERITIES.map((sev) => {
        if (!visibleSeverities.has(sev)) return null;
        const items = grouped.get(sev) ?? [];
        if (items.length === 0) return null;
        const style = ZOUIT_SEVERITY_STYLES[sev];

        return (
          <LayerGroup key={sev}>
            {items.map(({ overlap, geometry }, idx) => {
              const feature: Feature = {
                type: "Feature",
                geometry,
                properties: {},
              };
              const typeZone = overlap.type_zone ?? overlap.layer ?? null;
              return (
                <GeoJSON
                  // react-leaflet GeoJSON кэширует слой и не реагирует на смену
                  // data prop — геометрия в key форсирует remount при смене
                  // участка (тот же приём, что у изохрон/риск-зон в
                  // SiteMap/MarketLayers). slice(0,24) GeoJSON-строки тут НЕ
                  // годится: префикс `{"type":"Polygon","coord` константен и не
                  // зависит от координат, поэтому при A→B с тем же числом
                  // полигонов в том же порядке ключи совпадали и старая
                  // геометрия оставалась на карте. Берём строку целиком.
                  key={`zouit-${sev}-${idx}-${overlap.geom_geojson ?? ""}`}
                  data={feature}
                  style={{
                    color: style.color,
                    weight: 1.5,
                    fillColor: style.color,
                    fillOpacity: 0.3,
                  }}
                >
                  <Popup>
                    <div
                      style={{ fontSize: 12, lineHeight: 1.55, minWidth: 180 }}
                    >
                      <div
                        style={{
                          fontWeight: 700,
                          marginBottom: 4,
                          display: "flex",
                          alignItems: "center",
                          gap: 5,
                        }}
                      >
                        <span
                          style={{
                            display: "inline-block",
                            width: 10,
                            height: 10,
                            borderRadius: 2,
                            background: style.color,
                            flexShrink: 0,
                          }}
                        />
                        ЗОУИТ
                      </div>
                      {typeZone && (
                        <div style={{ marginBottom: 2 }}>
                          <strong>{typeZone}</strong>
                        </div>
                      )}
                      {overlap.name && overlap.name !== typeZone && (
                        <div style={{ color: "#374151", marginBottom: 2 }}>
                          {overlap.name}
                        </div>
                      )}
                      {overlap.reg_numb_border && (
                        <div
                          style={{
                            color: "#374151",
                            marginBottom: 2,
                            fontFamily: "monospace",
                          }}
                        >
                          Рег. №: {overlap.reg_numb_border}
                        </div>
                      )}
                      {typeof overlap.coverage_pct === "number" && (
                        <div style={{ color: "#374151", marginBottom: 2 }}>
                          Перекрытие участка:{" "}
                          <strong>
                            {Math.round(overlap.coverage_pct * 100)}%
                          </strong>
                        </div>
                      )}
                      {overlap.source && (
                        <div
                          style={{
                            marginTop: 4,
                            fontSize: 11,
                            color: "#9ca3af",
                            borderTop: "1px solid #f3f4f6",
                            paddingTop: 4,
                          }}
                        >
                          Источник: {overlap.source}
                        </div>
                      )}
                    </div>
                  </Popup>
                </GeoJSON>
              );
            })}
          </LayerGroup>
        );
      })}
    </>
  );
}
