/**
 * Unit tests for the #255 ЗОУИТ-layer pure logic: severity classification,
 * geom_geojson parsing (the graceful-skip contract), and grouping.
 *
 * The layer renders Leaflet <GeoJSON> (jsdom can't mount that meaningfully), so
 * we test the data-shaping that decides WHAT gets drawn and HOW it's colored —
 * that's where the bugs live (wrong severity → wrong color; bad parse → ocean
 * polygon or crash).
 */
import type { NspdZouitOverlap } from "@/types/nspd";
import {
  classifyZouit,
  groupZouitBySeverity,
  parseZouitGeometry,
} from "../ZouitLayer";

function overlap(partial: Partial<NspdZouitOverlap>): NspdZouitOverlap {
  return {
    group_key: "cad_zouit",
    layer: "",
    subcategory: null,
    name: null,
    ...partial,
  };
}

// A minimal valid GeoJSON Polygon string (как ST_AsGeoJSON отдаёт).
const POLYGON_STR = JSON.stringify({
  type: "Polygon",
  coordinates: [
    [
      [60.6, 56.83],
      [60.61, 56.83],
      [60.61, 56.84],
      [60.6, 56.83],
    ],
  ],
});

describe("classifyZouit", () => {
  it("classifies pipeline / electricity / gas zones as blocker", () => {
    expect(
      classifyZouit(overlap({ type_zone: "Охранная зона трубопровода" })),
    ).toBe("blocker");
    expect(
      classifyZouit(
        overlap({ type_zone: "Охранная зона электросетевого хозяйства" }),
      ),
    ).toBe("blocker");
    expect(
      classifyZouit(overlap({ type_zone: "Охранная зона газопровода" })),
    ).toBe("blocker");
  });

  it("classifies СЗЗ and heat-network zones as warning", () => {
    expect(
      classifyZouit(
        overlap({ type_zone: "Санитарно-защитная зона предприятия" }),
      ),
    ).toBe("warning");
    expect(
      classifyZouit(overlap({ type_zone: "Охранная зона тепловой сети" })),
    ).toBe("warning");
  });

  it("classifies servitude / unknown zones as info", () => {
    expect(
      classifyZouit(
        overlap({ type_zone: "Публичный сервитут в целях размещения сети" }),
      ),
    ).toBe("info");
    expect(classifyZouit(overlap({ type_zone: null, name: null }))).toBe(
      "info",
    );
  });

  it("falls back to name when type_zone is absent (nspd-dump path)", () => {
    expect(
      classifyZouit(overlap({ name: "Охранная зона трубопровода с кад. №…" })),
    ).toBe("blocker");
  });
});

describe("parseZouitGeometry", () => {
  it("parses a valid GeoJSON Polygon string", () => {
    const geom = parseZouitGeometry(POLYGON_STR);
    expect(geom?.type).toBe("Polygon");
  });

  it("returns null for missing / empty / invalid input (graceful skip)", () => {
    expect(parseZouitGeometry(null)).toBeNull();
    expect(parseZouitGeometry(undefined)).toBeNull();
    expect(parseZouitGeometry("")).toBeNull();
    expect(parseZouitGeometry("{not json")).toBeNull();
  });

  it("returns null for non-polygon geometry (Point/LineString not drawn)", () => {
    expect(
      parseZouitGeometry(
        JSON.stringify({ type: "Point", coordinates: [60.6, 56.83] }),
      ),
    ).toBeNull();
  });

  it("accepts an already-parsed object (contract tolerance)", () => {
    // Контракт — строка (ST_AsGeoJSON), но parseZouitGeometry терпит и объект на
    // случай смены контракта. Прогоняем object-путь через unknown-cast.
    const obj = JSON.parse(POLYGON_STR) as unknown;
    expect(parseZouitGeometry(obj as string)?.type).toBe("Polygon");
  });
});

describe("groupZouitBySeverity", () => {
  it("groups only mappable overlaps and drops geometry-less ones", () => {
    const grouped = groupZouitBySeverity([
      overlap({
        type_zone: "Охранная зона газопровода",
        geom_geojson: POLYGON_STR,
      }),
      overlap({
        type_zone: "Охранная зона тепловой сети",
        geom_geojson: POLYGON_STR,
      }),
      // Без geom_geojson — в карту не идёт.
      overlap({ type_zone: "Публичный сервитут", geom_geojson: null }),
    ]);
    expect(grouped.get("blocker")).toHaveLength(1);
    expect(grouped.get("warning")).toHaveLength(1);
    expect(grouped.get("info")).toHaveLength(0);
  });

  it("returns empty buckets (not undefined) when overlaps is empty", () => {
    const grouped = groupZouitBySeverity([]);
    expect(grouped.get("blocker")).toEqual([]);
    expect(grouped.get("warning")).toEqual([]);
    expect(grouped.get("info")).toEqual([]);
  });
});
