/**
 * Coordinate reprojection between EPSG:3844 (Stereo 70) and EPSG:4326 (WGS84).
 */

import proj4 from "proj4";
import type {
  GeoJsonFeatureCollection,
  GeoJsonMultiPolygon,
  GeoJsonPolygon,
} from "./esri-geojson";

const EPSG_3844_DEF =
  "+proj=sterea +lat_0=46 +lon_0=25 +k=0.99975 +x_0=500000 +y_0=500000 +ellps=GRS80 +units=m +no_defs";
const EPSG_4326_DEF = "+proj=longlat +datum=WGS84 +no_defs";

proj4.defs("EPSG:3844", EPSG_3844_DEF);
proj4.defs("EPSG:4326", EPSG_4326_DEF);

export const getEpsg3844Wkt = () =>
  'PROJCS["ETRS89 / Romania Stereo 70",GEOGCS["ETRS89",DATUM["European_Terrestrial_Reference_System_1989",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],AUTHORITY["EPSG","6258"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4258"]],PROJECTION["Oblique_Stereographic"],PARAMETER["latitude_of_origin",46],PARAMETER["central_meridian",25],PARAMETER["scale_factor",0.99975],PARAMETER["false_easting",500000],PARAMETER["false_northing",500000],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","3844"]]';

const reprojectCoords = (coords: number[][], from: string, to: string) =>
  coords.map(([x, y]) => {
    const [nx, ny] = proj4(from, to, [x!, y!]);
    return [nx!, ny!];
  });

const reprojectPolygon = (polygon: number[][][], from: string, to: string) =>
  polygon.map((ring) => reprojectCoords(ring, from, to));

export const reprojectFeatureCollection = (
  collection: GeoJsonFeatureCollection,
  from: string,
  to: string,
): GeoJsonFeatureCollection => {
  if (from === to) return collection;

  const features = collection.features.map((feature) => {
    if (!feature.geometry) return feature;

    if (feature.geometry.type === "Polygon") {
      const geometry: GeoJsonPolygon = {
        type: "Polygon",
        coordinates: reprojectPolygon(feature.geometry.coordinates, from, to),
      };
      return { ...feature, geometry };
    }

    const geometry: GeoJsonMultiPolygon = {
      type: "MultiPolygon",
      coordinates: feature.geometry.coordinates.map((polygon) =>
        reprojectPolygon(polygon, from, to),
      ),
    };
    return { ...feature, geometry };
  });

  return { ...collection, features };
};
