/**
 * Unit tests for the parcel-geometry narrowers in concept-api.ts.
 *
 * These guard the §7 «Размещение застройки» multi-part fix:
 *  • `extractPolygon` (the /concepts REQUEST geometry) must collapse a
 *    MultiPolygon to its LARGEST-area part, not `coordinates[0]` (which can be a
 *    sliver), so the generated corpus sits on the dominant part.
 *  • `extractParcelGeometry` (the SCENE geometry) must preserve EVERY part so the
 *    outline / projection origin / OSM tile cover the whole parcel and stay
 *    geo-aligned with backend-anchored neighbours.
 */
import type { MultiPolygon, Polygon, Position } from "geojson";
import { describe, expect, it } from "vitest";

import { extractParcelGeometry, extractPolygon } from "../concept-api";

// Part 0: a small sliver near the origin (≈55 m × 55 m).
const SLIVER: Position[] = [
  [60.6, 56.83],
  [60.6005, 56.83],
  [60.6005, 56.8305],
  [60.6, 56.8305],
  [60.6, 56.83],
];
// Part 1: a much larger square ~1 km east (the dominant part).
const MAIN: Position[] = [
  [60.616, 56.83],
  [60.62, 56.83],
  [60.62, 56.834],
  [60.616, 56.834],
  [60.616, 56.83],
];

const MULTI: MultiPolygon = {
  type: "MultiPolygon",
  coordinates: [[SLIVER], [MAIN]],
};

describe("extractPolygon — /concepts request geometry", () => {
  it("returns a bare Polygon unchanged", () => {
    const poly: Polygon = { type: "Polygon", coordinates: [MAIN] };
    expect(extractPolygon(poly)).toEqual(poly);
  });

  it("unwraps a Feature wrapping a Polygon", () => {
    const result = extractPolygon({
      type: "Feature",
      properties: {},
      geometry: { type: "Polygon", coordinates: [MAIN] },
    });
    expect(result).toEqual({ type: "Polygon", coordinates: [MAIN] });
  });

  it("collapses a MultiPolygon to its LARGEST part, not coordinates[0]", () => {
    const result = extractPolygon(MULTI);
    expect(result).not.toBeNull();
    expect(result?.type).toBe("Polygon");
    // Must pick MAIN (part 1), NOT the SLIVER at index 0.
    expect(result?.coordinates).toEqual([MAIN]);
    expect(result?.coordinates).not.toEqual([SLIVER]);
  });

  it("returns null on a non-polygonal / malformed shape", () => {
    expect(extractPolygon(null)).toBeNull();
    expect(extractPolygon({ type: "Point", coordinates: [1, 2] })).toBeNull();
    expect(extractPolygon("nope")).toBeNull();
  });
});

describe("extractParcelGeometry — whole scene geometry", () => {
  it("returns a bare Polygon unchanged", () => {
    const poly: Polygon = { type: "Polygon", coordinates: [MAIN] };
    expect(extractParcelGeometry(poly)).toEqual(poly);
  });

  it("preserves EVERY part of a MultiPolygon (both parts, not just part 0)", () => {
    const result = extractParcelGeometry(MULTI);
    expect(result).not.toBeNull();
    expect(result?.type).toBe("MultiPolygon");
    const mp = result as MultiPolygon;
    expect(mp.coordinates).toHaveLength(2);
    expect(mp.coordinates[0]).toEqual([SLIVER]);
    expect(mp.coordinates[1]).toEqual([MAIN]);
  });

  it("unwraps a Feature wrapping a MultiPolygon", () => {
    const result = extractParcelGeometry({
      type: "Feature",
      properties: {},
      geometry: MULTI,
    });
    expect(result?.type).toBe("MultiPolygon");
    expect((result as MultiPolygon).coordinates).toHaveLength(2);
  });

  it("returns null on a non-polygonal / malformed shape", () => {
    expect(extractParcelGeometry(null)).toBeNull();
    expect(
      extractParcelGeometry({ type: "LineString", coordinates: [] }),
    ).toBeNull();
  });
});
