/**
 * #1953 — unit tests for buildUtilityTableRows (таблица §3 «Сети»).
 *
 * Ключевое свойство, которое проверяем: count в строке таблицы по каждому виду
 * == число РИСУЕМЫХ объектов этого вида (тот же groupUtilityByKind, что у карты).
 * Поэтому достаточно сравнить счётчики строк с прямой группировкой features —
 * если они расходятся, счётчики таблица↔карта снова разъедутся (исходный баг).
 *
 * Также: nearest = минимум distance_m по рисуемым features вида; виды без
 * рисуемых объектов опускаются; невалидная геометрия не считается.
 */
import type { UtilityInfrastructureFeature } from "@/hooks/useUtilityInfrastructure";
import { groupUtilityByKind } from "../../UtilityInfrastructureLayer";
import { buildUtilityTableRows } from "../utility-table";

function feat(
  partial: Partial<UtilityInfrastructureFeature>,
): UtilityInfrastructureFeature {
  return {
    osm_id: 1,
    osm_type: "way",
    infrastructure_kind: "power",
    name: null,
    source_tag: null,
    distance_m: 0,
    geometry_geojson: { type: "Point", coordinates: [60.6, 56.83] },
    ...partial,
  };
}

const POINT = { type: "Point", coordinates: [60.6, 56.83] };
const LINE = {
  type: "LineString",
  coordinates: [
    [60.6, 56.83],
    [60.61, 56.84],
  ],
};

describe("buildUtilityTableRows", () => {
  it("row count per kind == groupUtilityByKind count (счётчики == карта)", () => {
    const features = [
      feat({
        infrastructure_kind: "power",
        geometry_geojson: LINE,
        distance_m: 120,
      }),
      feat({
        infrastructure_kind: "power",
        geometry_geojson: POINT,
        distance_m: 40,
      }),
      feat({
        infrastructure_kind: "gas",
        geometry_geojson: LINE,
        distance_m: 300,
      }),
      feat({
        infrastructure_kind: "water",
        geometry_geojson: POINT,
        distance_m: 800,
      }),
    ];

    const rows = buildUtilityTableRows(features);
    const grouped = groupUtilityByKind(features);

    for (const row of rows) {
      expect(row.count).toBe(grouped.get(row.kind)!.length);
    }
    // Сумма строк = число рисуемых объектов на карте.
    const total = rows.reduce((s, r) => s + r.count, 0);
    const mapTotal = [...grouped.values()].reduce((s, v) => s + v.length, 0);
    expect(total).toBe(mapTotal);
  });

  it("nearestM = минимум distance_m по рисуемым features вида", () => {
    const rows = buildUtilityTableRows([
      feat({
        infrastructure_kind: "power",
        geometry_geojson: LINE,
        distance_m: 120,
      }),
      feat({
        infrastructure_kind: "power",
        geometry_geojson: POINT,
        distance_m: 40,
      }),
    ]);
    const power = rows.find((r) => r.kind === "power");
    expect(power?.count).toBe(2);
    expect(power?.nearestM).toBe(40);
  });

  it("опускает виды без рисуемых объектов; порядок — power первым", () => {
    const rows = buildUtilityTableRows([
      feat({
        infrastructure_kind: "gas",
        geometry_geojson: LINE,
        distance_m: 10,
      }),
      feat({
        infrastructure_kind: "power",
        geometry_geojson: LINE,
        distance_m: 10,
      }),
    ]);
    expect(rows.map((r) => r.kind)).toEqual(["power", "gas"]);
  });

  it("не считает features с невалидной геометрией (не рисуются → не в счётчике)", () => {
    const rows = buildUtilityTableRows([
      feat({
        infrastructure_kind: "power",
        geometry_geojson: LINE,
        distance_m: 50,
      }),
      feat({
        infrastructure_kind: "power",
        geometry_geojson: {},
        distance_m: 5,
      }),
    ]);
    const power = rows.find((r) => r.kind === "power");
    expect(power?.count).toBe(1);
    // nearest НЕ 5 (тот объект не рисуется), а 50.
    expect(power?.nearestM).toBe(50);
  });

  it("неизвестный вид → строка 'other' с человеческой подписью", () => {
    const rows = buildUtilityTableRows([
      feat({
        infrastructure_kind: "telecom",
        geometry_geojson: POINT,
        distance_m: 200,
      }),
    ]);
    expect(rows).toHaveLength(1);
    expect(rows[0].kind).toBe("other");
    expect(rows[0].label).toBe("Прочее");
  });

  it("пустой ввод → пустой массив (graceful empty-state)", () => {
    expect(buildUtilityTableRows([])).toEqual([]);
  });
});
