/**
 * ESRI → GeoJSON conversion for eTerra features.
 */

import type { EsriFeature } from "./eterra-client";

export type GeoJsonPolygon = { type: "Polygon"; coordinates: number[][][] };
export type GeoJsonMultiPolygon = {
  type: "MultiPolygon";
  coordinates: number[][][][];
};

export type GeoJsonFeature = {
  type: "Feature";
  properties: Record<string, unknown>;
  geometry: GeoJsonPolygon | GeoJsonMultiPolygon | null;
};

export type GeoJsonFeatureCollection = {
  type: "FeatureCollection";
  features: GeoJsonFeature[];
};

const ringArea = (ring: number[][]) => {
  let area = 0;
  for (let i = 0; i < ring.length - 1; i++) {
    const curr = ring[i]!;
    const next = ring[i + 1]!;
    area += curr[0]! * next[1]! - next[0]! * curr[1]!;
  }
  return area / 2;
};

const isClockwise = (ring: number[][]) => ringArea(ring) < 0;

const closeRing = (ring: number[][]) => {
  if (ring.length === 0) return ring;
  const first = ring[0]!;
  const last = ring[ring.length - 1]!;
  return first[0] !== last[0] || first[1] !== last[1]
    ? [...ring, [first[0]!, first[1]!]]
    : ring;
};

const ringsToPolygons = (rings: number[][][]) => {
  const polygons: number[][][][] = [];
  let current: number[][][] | null = null;
  for (const ring of rings) {
    const closed = closeRing(ring);
    if (closed.length < 4) continue;
    if (isClockwise(closed) || !current) {
      if (current) polygons.push(current);
      current = [closed];
    } else {
      current.push(closed);
    }
  }
  if (current) polygons.push(current);
  return polygons;
};

export const esriToGeojson = (
  features: EsriFeature[],
): GeoJsonFeatureCollection => {
  const geoFeatures: GeoJsonFeature[] = [];
  for (const feature of features) {
    const rings = feature.geometry?.rings;
    if (!rings?.length) continue;
    const polygons = ringsToPolygons(rings);
    if (!polygons.length) continue;
    const geometry: GeoJsonPolygon | GeoJsonMultiPolygon =
      polygons.length === 1
        ? { type: "Polygon", coordinates: polygons[0]! }
        : { type: "MultiPolygon", coordinates: polygons };
    geoFeatures.push({
      type: "Feature",
      properties: feature.attributes ?? {},
      geometry,
    });
  }
  return { type: "FeatureCollection", features: geoFeatures };
};
