import type { Feature, FeatureCollection, Polygon, Point, Position } from "geojson";
import type {
  IndexedTins,
  Tins,
  VerticesParams,
  WeightBuffer
} from "./geometry.ts";
import type { EdgeSet, EdgeSetLegacy } from "./edgeutils.ts";

/**
 * Two-way coordinate pair: [source, target].
 */
export type PointSet = [Position, Position];

/**
 * Directional selector shared across the codebase.
 */
export type BiDirectionKey = "forw" | "bakw";

/**
 * Weight buffers indexed by node id for both directions.
 */
export type WeightBufferBD = { [key in BiDirectionKey]?: WeightBuffer };

/**
 * Vertex interpolation modes.
 */
export type VertexMode = "plain" | "birdeye";

/**
 * Strictness flags supported during transformation.
 */
export type StrictMode = "strict" | "auto" | "loose";

/**
 * Result of strictness evaluation.
 */
export type StrictStatus = "strict" | "strict_error" | "loose";

/**
 * Y-axis handling directive.
 */
export type YaxisMode = "follow" | "invert";

export type Centroid = Feature<Point>;
export type CentroidBD = { [key in BiDirectionKey]?: Centroid };
export type TinsBD = { [key in BiDirectionKey]?: Tins };
export type Kinks = FeatureCollection<Point>;
export type KinksBD = { [key in BiDirectionKey]?: Kinks };
export type VerticesParamsBD = { [key in BiDirectionKey]?: VerticesParams };
export type IndexedTinsBD = { [key in BiDirectionKey]?: IndexedTins };

/**
 * Serialized structure generated by MaplatTin and consumed by Transform.
 */
export interface Compiled {
  version?: number;
  points: PointSet[];
  tins_points: (number | string)[][][];
  weight_buffer: WeightBufferBD;
  strict_status?: StrictStatus;
  centroid_point: Position[];
  edgeNodes?: PointSet[];
  kinks_points?: Position[];
  yaxisMode?: YaxisMode;
  vertexMode?: VertexMode;
  strictMode?: StrictMode;
  vertices_params: number[][];
  vertices_points: PointSet[];
  edges?: EdgeSet[];
  bounds?: number[][];
  boundsPolygon?: Feature<Polygon>;
  wh?: number[];
  xy?: number[];
}

/**
 * Historical serialization format prior to 2.00703.
 */
export interface CompiledLegacy extends Compiled {
  tins?: TinsBD;
  centroid?: CentroidBD;
  kinks?: KinksBD;
  vertices_params: number[][] & VerticesParamsBD;
  edges: EdgeSet[] & EdgeSetLegacy[];
}

/**
 * Normalized state derived from modern compiled payloads.
 */
export interface ModernStatePayload {
  points: PointSet[];
  pointsWeightBuffer: WeightBufferBD;
  strictStatus: StrictStatus;
  verticesParams: VerticesParamsBD;
  centroid: CentroidBD;
  edges: EdgeSet[];
  edgeNodes?: PointSet[];
  tins: TinsBD;
  kinks?: KinksBD;
  yaxisMode: YaxisMode;
  strictMode: StrictMode;
  vertexMode?: VertexMode;
  bounds?: number[][];
  boundsPolygon?: Feature<Polygon>;
  wh?: number[];
  xy?: number[];
}

/**
 * Normalized snapshot captured from legacy payloads.
 */
export interface LegacyStatePayload {
  compiled: CompiledLegacy;
  tins: TinsBD;
  points: PointSet[];
  strictStatus?: StrictStatus;
  pointsWeightBuffer: WeightBufferBD;
  verticesParams: VerticesParamsBD;
  centroid?: CentroidBD;
  kinks?: KinksBD;
}

// ─── MapTransform types ───────────────────────────────────────────────────────

/**
 * Viewport representation: center in mercator, zoom level, rotation in radians.
 */
export interface Viewpoint {
  /** Mercator coordinate [x, y] */
  center: number[];
  /** Mercator zoom level */
  zoom: number;
  /** Rotation angle in radians */
  rotation: number;
}

/**
 * Sub-map TIN data for MapTransform.setMapData().
 */
export interface SubMapData {
  /** Compiled TIN data */
  compiled: Compiled;
  /** Layer priority (higher = checked first) */
  priority: number;
  /** Layer importance (used when multiple layers overlap) */
  importance: number;
  /** Bounds vertices in pixel (XY) space. Falls back to compiled.bounds if omitted. */
  bounds?: number[][];
}

/**
 * Input data for MapTransform.setMapData().
 */
export interface MapData {
  /** Compiled TIN data for the main layer */
  compiled: Compiled;
  /** maxZoom value used to compute _maxxy = 2^maxZoom * 256 */
  maxZoom?: number;
  /** Sub-map layers */
  sub_maps?: SubMapData[];
}
