import type { FeatureCollection } from "geojson";
import { GEOSERVER_WORKSPACE, MAP_URL } from "./geoserver-config";
import {
  SOURCE_LAYERS,
  isAvailableWaterNetworkSourceId,
  type WaterNetworkSourceId
} from "./sources";

export const MAP_FEATURE_ID_FIELDS: Record<WaterNetworkSourceId, "id"> = {
  pipes: "id",
  junctions: "id",
  valves: "id",
  reservoirs: "id",
  scada: "id",
  pumps: "id",
  tanks: "id"
};

export const MAX_MAP_FEATURE_IDS = 100;
export const MAX_MAP_FEATURE_ID_LENGTH = 128;
export const MAX_PIPE_FEATURES = 5000;

export type MapFeatureQuery = {
  sourceId: WaterNetworkSourceId;
  featureIds?: string[];
};

export type MapFeatureQueryValidation =
  | { ok: true; value: MapFeatureQuery }
  | { ok: false; code: "INVALID_REQUEST" | "UNSUPPORTED_SOURCE"; status: 400 | 422 };

export function parseMapFeatureQuery(body: unknown): MapFeatureQueryValidation {
  if (!body || typeof body !== "object") {
    return { ok: false, code: "INVALID_REQUEST", status: 400 };
  }

  const { sourceId, featureIds } = body as { sourceId?: unknown; featureIds?: unknown };
  if (typeof sourceId !== "string" || !(sourceId in SOURCE_LAYERS) || !isAvailableWaterNetworkSourceId(sourceId)) {
    return { ok: false, code: "UNSUPPORTED_SOURCE", status: 422 };
  }

  if (featureIds === undefined) {
    return sourceId === "pipes"
      ? { ok: true, value: { sourceId } }
      : { ok: false, code: "INVALID_REQUEST", status: 400 };
  }

  if (
    !Array.isArray(featureIds) ||
    featureIds.length < 1 ||
    featureIds.length > MAX_MAP_FEATURE_IDS ||
    !featureIds.every(
      (id) => typeof id === "string" && id.trim().length > 0 && id.trim().length <= MAX_MAP_FEATURE_ID_LENGTH
    )
  ) {
    return { ok: false, code: "INVALID_REQUEST", status: 400 };
  }

  return {
    ok: true,
    value: { sourceId: sourceId as WaterNetworkSourceId, featureIds: featureIds.map((id) => id.trim()) }
  };
}

export function escapeCqlLiteral(value: string) {
  return `'${value.replaceAll("'", "''")}'`;
}

export function createMapFeatureWfsUrl(query: MapFeatureQuery) {
  const idField = MAP_FEATURE_ID_FIELDS[query.sourceId];
  const params = new URLSearchParams({
    service: "WFS",
    version: "2.0.0",
    request: "GetFeature",
    typeNames: `${GEOSERVER_WORKSPACE}:${SOURCE_LAYERS[query.sourceId]}`,
    outputFormat: "application/json",
    srsName: "EPSG:4326",
    count: String(query.featureIds ? MAX_MAP_FEATURE_IDS : MAX_PIPE_FEATURES)
  });

  if (query.featureIds) {
    params.set("cql_filter", `"${idField}" IN (${query.featureIds.map(escapeCqlLiteral).join(",")})`);
  }

  return new URL(`${MAP_URL}/${GEOSERVER_WORKSPACE}/ows?${params.toString()}`);
}

export function normalizeMapFeatureCollection(value: unknown, maxFeatures: number): FeatureCollection | null {
  if (!value || typeof value !== "object") return null;
  const collection = value as FeatureCollection;
  if (collection.type !== "FeatureCollection" || !Array.isArray(collection.features)) return null;
  return { type: "FeatureCollection", features: collection.features.slice(0, maxFeatures) };
}
