"use client";

import { CircleMarker, Popup, LayerGroup } from "react-leaflet";

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

// ---------------------------------------------------------------------------
// Category classification
// ---------------------------------------------------------------------------

export type CpCategory =
  "electricity" | "gas" | "water" | "heat" | "sewage" | "telecom" | "other";

export interface CpCategoryStyle {
  color: string;
  label: string;
  radius: number;
}

export const CP_CATEGORY_STYLES: Record<CpCategory, CpCategoryStyle> = {
  electricity: { color: "#f59e0b", label: "Электричество", radius: 9 },
  gas: { color: "#3b82f6", label: "Газ", radius: 9 },
  water: { color: "#06b6d4", label: "Вода", radius: 8 },
  heat: { color: "#ef4444", label: "Теплоснабжение", radius: 8 },
  sewage: { color: "#8b5cf6", label: "Канализация", radius: 8 },
  telecom: { color: "#10b981", label: "Связь", radius: 7 },
  other: { color: "#6b7280", label: "Другое", radius: 7 },
};

export const CP_ALL_CATEGORIES = Object.keys(
  CP_CATEGORY_STYLES,
) as CpCategory[];

// Keywords to match against `type` and `name` fields (case-insensitive)
const CATEGORY_KEYWORDS: Array<{ cat: CpCategory; keywords: string[] }> = [
  {
    cat: "electricity",
    keywords: [
      "трансформатор",
      "тп-",
      "ктп",
      "подстанция",
      "электр",
      "tp-",
      "лэп",
      "36328",
    ],
  },
  {
    cat: "gas",
    keywords: ["газ", "гтс", "газоп", "газорегул", "газопровод"],
  },
  {
    cat: "water",
    keywords: ["водо", "водопр", "насосн", "колодец", "скважин"],
  },
  {
    cat: "heat",
    keywords: ["тепло", "теплос", "котельн", "тэц"],
  },
  {
    cat: "sewage",
    keywords: ["канал", "сток", "ливнев", "кнс", "канализ"],
  },
  {
    cat: "telecom",
    keywords: ["связ", "телеком", "интернет", "оптик", "вышка"],
  },
];

export function classifyStructure(s: EngineeringStructure): CpCategory {
  const haystack =
    `${s.name ?? ""} ${s.type ?? ""} ${s.source ?? ""}`.toLowerCase();
  for (const { cat, keywords } of CATEGORY_KEYWORDS) {
    if (keywords.some((kw) => haystack.includes(kw))) return cat;
  }
  return "other";
}

// ---------------------------------------------------------------------------
// Group helper (exported so SiteMap can build counts for the control panel)
// ---------------------------------------------------------------------------

export function groupStructuresByCategory(
  structures: EngineeringStructure[],
): Map<CpCategory, EngineeringStructure[]> {
  const grouped = new Map<CpCategory, EngineeringStructure[]>();
  for (const cat of CP_ALL_CATEGORIES) {
    grouped.set(cat, []);
  }
  for (const s of structures) {
    const cat = classifyStructure(s);
    grouped.get(cat)!.push(s);
  }
  return grouped;
}

// ---------------------------------------------------------------------------
// Geometry helpers
// ---------------------------------------------------------------------------
//
// #1961 — NSPD engineering_structures (cat 36328 — ТП/ЦТП/насосные/опоры ЛЭП)
// приходят как Polygon/MultiPolygon (контуры сооружений), НЕ как Point — в
// проде 587 Polygon + 298 MultiPolygon и НОЛЬ Point. Старый extractLatLon
// обрабатывал только Point → слой точек подключения был всегда пуст.
//
// Вдобавок geometry_geojson этих объектов хранится/отдаётся в EPSG:3857
// (Web-Mercator: x≈6.7e6, y≈7.7e6), а карта (участок + OSM-слой) — в EPSG:4326.
// Без репроекции центроид улетал бы в Атлантику. Репроецируем 3857→4326 на
// фронте (чистая математика, без изменений бэка). Эвристика CRS: если |x|>180
// или |y|>90 — это метры (3857), иначе уже градусы (4326).

const EARTH_RADIUS_M = 6378137; // WGS84 большая полуось — как в EPSG:3857
const ORIGIN_SHIFT = Math.PI * EARTH_RADIUS_M; // 20037508.342789244

/** EPSG:3857 (метры) → EPSG:4326 [lon, lat] (градусы). */
function mercatorToLonLat(x: number, y: number): [number, number] {
  const lon = (x / ORIGIN_SHIFT) * 180;
  const lat =
    (Math.atan(Math.exp((y / ORIGIN_SHIFT) * Math.PI)) * 360) / Math.PI - 90;
  return [lon, lat];
}

/** Эвристика: координаты вне диапазона градусов → это метры (Web-Mercator). */
function looksLikeMercator(x: number, y: number): boolean {
  return Math.abs(x) > 180 || Math.abs(y) > 90;
}

/** [x|lon, y|lat] любого CRS → [lat, lon] (4326) для Leaflet. */
function toLeafletLatLon(pos: number[]): [number, number] | null {
  if (pos.length < 2) return null;
  const [x, y] = pos;
  if (typeof x !== "number" || typeof y !== "number") return null;
  if (looksLikeMercator(x, y)) {
    const [lon, lat] = mercatorToLonLat(x, y);
    return [lat, lon];
  }
  // Уже градусы: GeoJSON-порядок [lon, lat] → Leaflet [lat, lon].
  return [y, x];
}

/**
 * Среднее по координатам внешнего кольца(колец) полигона — достаточно для
 * маркера-точки внутри/рядом с небольшим сооружением (ТП ≈ 10-30 м).
 */
function ringCentroid(rings: number[][]): [number, number] | null {
  let sumX = 0;
  let sumY = 0;
  let n = 0;
  for (const p of rings) {
    if (p.length < 2 || typeof p[0] !== "number" || typeof p[1] !== "number") {
      continue;
    }
    sumX += p[0];
    sumY += p[1];
    n += 1;
  }
  if (n === 0) return null;
  return toLeafletLatLon([sumX / n, sumY / n]);
}

/**
 * Возвращает [lat, lon] (4326) представительной точки геометрии:
 *   Point        → сама точка
 *   Polygon      → центроид внешнего кольца coordinates[0]
 *   MultiPolygon → центроид внешнего кольца первого полигона
 * CRS (3857 vs 4326) определяется автоматически (см. toLeafletLatLon).
 * Возвращает null для пустой/невалидной геометрии — маркер тогда не рисуется.
 */
export function extractLatLon(
  geojson: Record<string, unknown>,
): [number, number] | null {
  const type = geojson.type;
  const coords = geojson.coordinates;

  if (type === "Point") {
    if (Array.isArray(coords) && coords.length >= 2) {
      return toLeafletLatLon(coords as number[]);
    }
    return null;
  }

  if (type === "Polygon") {
    // coordinates: number[][][] — берём внешнее кольцо [0].
    const outer = Array.isArray(coords)
      ? (coords as number[][][])[0]
      : undefined;
    if (Array.isArray(outer)) return ringCentroid(outer);
    return null;
  }

  if (type === "MultiPolygon") {
    // coordinates: number[][][][] — внешнее кольцо первого полигона [0][0].
    const outer = Array.isArray(coords)
      ? (coords as number[][][][])[0]?.[0]
      : undefined;
    if (Array.isArray(outer)) return ringCentroid(outer);
    return null;
  }

  return null;
}

// ---------------------------------------------------------------------------
// Map layer — renders CircleMarkers inside the Leaflet MapContainer
// ---------------------------------------------------------------------------

interface LayerProps {
  visibleCategories: Set<CpCategory>;
  grouped: Map<CpCategory, EngineeringStructure[]>;
}

export function ConnectionPointsLayer({
  visibleCategories,
  grouped,
}: LayerProps) {
  return (
    <>
      {CP_ALL_CATEGORIES.map((cat) => {
        if (!visibleCategories.has(cat)) return null;
        const structs = grouped.get(cat) ?? [];
        const style = CP_CATEGORY_STYLES[cat];

        return (
          <LayerGroup key={cat}>
            {structs.map((s, idx) => {
              const latLon = extractLatLon(s.geometry_geojson);
              if (!latLon) return null;

              return (
                <CircleMarker
                  key={`cp-${cat}-${idx}`}
                  center={latLon}
                  radius={style.radius}
                  pathOptions={{
                    color: style.color,
                    fillColor: style.color,
                    fillOpacity: 0.9,
                    weight: 2,
                  }}
                >
                  {/* Попап точки подключения (НСПД). Атрибуты из options дампа:
                      категория, название (params_name, напр. «КЛ 10кВ ТП…»),
                      назначение (params_purpose), характеристики (год /
                      протяжённость / собственность), адрес, расстояние, источник.
                      Отдельных полей напряжения/диаметра нет — если есть, они в
                      названии (params_name); не выдумываем. */}
                  <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: "50%",
                            background: style.color,
                            flexShrink: 0,
                          }}
                        />
                        {style.label}
                      </div>
                      <div
                        style={{
                          color: "#6b7280",
                          marginBottom: 4,
                          fontSize: 11,
                        }}
                      >
                        Точка подключения (НСПД)
                      </div>
                      <div style={{ marginBottom: 2 }}>
                        <strong>{s.name ?? s.type ?? "Объект"}</strong>
                      </div>
                      {s.type && s.name && (
                        <div style={{ color: "#6b7280", marginBottom: 2 }}>
                          Тип: {s.type}
                        </div>
                      )}
                      {s.purpose && (
                        <div style={{ color: "#6b7280", marginBottom: 2 }}>
                          Назначение: {s.purpose}
                        </div>
                      )}
                      {s.characteristics && (
                        <div style={{ color: "#6b7280", marginBottom: 2 }}>
                          {s.characteristics}
                        </div>
                      )}
                      {s.readable_address && (
                        <div style={{ color: "#374151", marginBottom: 2 }}>
                          {s.readable_address}
                        </div>
                      )}
                      {s.cad_num && (
                        <div
                          style={{
                            color: "#9ca3af",
                            marginBottom: 2,
                            fontSize: 11,
                          }}
                        >
                          № ЕГРН: {s.cad_num}
                        </div>
                      )}
                      <div style={{ marginTop: 4, color: "#374151" }}>
                        До границы участка:{" "}
                        <strong>
                          {Math.round(s.distance_to_boundary_m)} м
                        </strong>
                      </div>
                      <div
                        style={{
                          marginTop: 4,
                          fontSize: 11,
                          color: "#9ca3af",
                          borderTop: "1px solid #f3f4f6",
                          paddingTop: 4,
                        }}
                      >
                        Источник: {s.source}
                      </div>
                    </div>
                  </Popup>
                </CircleMarker>
              );
            })}
          </LayerGroup>
        );
      })}
    </>
  );
}
