/**
 * POST /api/eterra/export-local
 *
 * Export features from local PostgreSQL database as GPKG / ZIP.
 * No eTerra connection needed — serves from previously synced data.
 *
 * Modes:
 *   - base:  ZIP with terenuri.gpkg + cladiri.gpkg
 *   - magic: ZIP with terenuri.gpkg + cladiri.gpkg + terenuri_magic.gpkg
 *            + terenuri_complet.csv + raport_calitate.txt + export_report.json
 *   - layer: single layer GPKG (legacy, layerIds/allLayers)
 *
 * Body: { siruta, mode?: "base"|"magic", layerIds?: string[], allLayers?: boolean }
 */
import { prisma } from "@/core/storage/prisma";
import { buildGpkg } from "@/modules/parcel-sync/services/gpkg-export";
import { getEpsg3844Wkt } from "@/modules/parcel-sync/services/reproject";
import { findLayerById } from "@/modules/parcel-sync/services/eterra-layers";
import type { GeoJsonFeature } from "@/modules/parcel-sync/services/esri-geojson";
import type { FeatureEnrichment } from "@/modules/parcel-sync/services/enrich-service";
import JSZip from "jszip";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

type Body = {
  siruta?: string;
  mode?: "base" | "magic";
  layerIds?: string[];
  allLayers?: boolean;
};

const csvEscape = (val: unknown) => {
  const s = String(val ?? "").replace(/"/g, '""');
  return `"${s}"`;
};

export async function POST(req: Request) {
  try {
    const body = (await req.json()) as Body;
    const siruta = String(body.siruta ?? "").trim();

    if (!siruta || !/^\d+$/.test(siruta)) {
      return Response.json({ error: "SIRUTA invalid" }, { status: 400 });
    }

    // ── New: "base" or "magic" mode → full ZIP from DB ──
    if (body.mode === "base" || body.mode === "magic") {
      return buildFullZip(siruta, body.mode);
    }

    // ── Legacy: single/multi layer GPKG ──
    let layerIds: string[];
    if (body.layerIds?.length) {
      layerIds = body.layerIds;
    } else if (body.allLayers) {
      const layerGroups = await prisma.gisFeature.groupBy({
        by: ["layerId"],
        where: { siruta },
        _count: { id: true },
      });
      layerIds = layerGroups
        .filter((g) => g._count.id > 0)
        .map((g) => g.layerId);
    } else {
      return Response.json(
        { error: "Specifică mode, layerIds, sau allLayers=true" },
        { status: 400 },
      );
    }

    if (layerIds.length === 0) {
      return Response.json(
        { error: "Niciun layer sincronizat în baza de date pentru acest UAT" },
        { status: 404 },
      );
    }

    if (layerIds.length === 1) {
      const layerId = layerIds[0]!;
      const gpkg = await buildLayerGpkg(siruta, layerId);
      const layer = findLayerById(layerId);
      const filename = `eterra_local_${siruta}_${layer?.name ?? layerId}.gpkg`;
      return new Response(new Uint8Array(gpkg), {
        headers: {
          "Content-Type": "application/geopackage+sqlite3",
          "Content-Disposition": `attachment; filename="${filename}"`,
        },
      });
    }

    const zip = new JSZip();
    for (const layerId of layerIds) {
      const gpkg = await buildLayerGpkg(siruta, layerId);
      const layer = findLayerById(layerId);
      zip.file(`${layer?.name ?? layerId}.gpkg`, gpkg);
    }
    const zipBuf = await zip.generateAsync({ type: "nodebuffer" });
    return new Response(new Uint8Array(zipBuf), {
      headers: {
        "Content-Type": "application/zip",
        "Content-Disposition": `attachment; filename="eterra_local_${siruta}.zip"`,
      },
    });
  } catch (error) {
    const message = error instanceof Error ? error.message : "Eroare server";
    return Response.json({ error: message }, { status: 500 });
  }
}

/* ────────────────────────────────────────────────────────── */
/*  Full ZIP export from DB (base / magic)                     */
/* ────────────────────────────────────────────────────────── */

async function buildFullZip(siruta: string, mode: "base" | "magic") {
  const srsWkt = getEpsg3844Wkt();

  // Load from DB
  const dbTerenuri = await prisma.gisFeature.findMany({
    where: { layerId: "TERENURI_ACTIVE", siruta },
    select: {
      attributes: true,
      geometry: true,
      enrichment: true,
      geometrySource: true,
    },
  });
  const dbCladiri = await prisma.gisFeature.findMany({
    where: { layerId: "CLADIRI_ACTIVE", siruta },
    select: { attributes: true, geometry: true },
  });

  if (dbTerenuri.length === 0 && dbCladiri.length === 0) {
    return Response.json(
      {
        error:
          "Baza de date este goală pentru acest UAT. Rulează sincronizarea mai întâi.",
      },
      { status: 404 },
    );
  }

  const toGeoFeatures = (
    records: { attributes: unknown; geometry: unknown }[],
  ): GeoJsonFeature[] =>
    records
      .filter((r) => r.geometry != null)
      .map((r) => ({
        type: "Feature" as const,
        geometry: r.geometry as GeoJsonFeature["geometry"],
        properties: r.attributes as Record<string, unknown>,
      }));

  const terenuriGeo = toGeoFeatures(dbTerenuri);
  const cladiriGeo = toGeoFeatures(dbCladiri);

  const terenuriFields =
    terenuriGeo.length > 0 ? Object.keys(terenuriGeo[0]!.properties) : [];
  const cladiriFields =
    cladiriGeo.length > 0 ? Object.keys(cladiriGeo[0]!.properties) : [];

  const terenuriGpkg = await buildGpkg({
    srsId: 3844,
    srsWkt,
    layers: [
      {
        name: "TERENURI_ACTIVE",
        fields: terenuriFields,
        features: terenuriGeo,
      },
    ],
  });
  const cladiriGpkg = await buildGpkg({
    srsId: 3844,
    srsWkt,
    layers: [
      { name: "CLADIRI_ACTIVE", fields: cladiriFields, features: cladiriGeo },
    ],
  });

  const zip = new JSZip();
  zip.file("terenuri.gpkg", terenuriGpkg);
  zip.file("cladiri.gpkg", cladiriGpkg);

  // DXF versions (non-fatal — ogr2ogr may not be available)
  const { gpkgToDxf } = await import(
    "@/modules/parcel-sync/services/gpkg-export"
  );
  const terenuriDxf = await gpkgToDxf(terenuriGpkg, "TERENURI_ACTIVE");
  if (terenuriDxf) zip.file("terenuri.dxf", terenuriDxf);
  const cladiriDxf = await gpkgToDxf(cladiriGpkg, "CLADIRI_ACTIVE");
  if (cladiriDxf) zip.file("cladiri.dxf", cladiriDxf);

  if (mode === "magic") {
    // ── Magic: enrichment-merged GPKG + CSV + quality report ──
    const headers = [
      "OBJECTID",
      "IMMOVABLE_ID",
      "APPLICATION_ID",
      "NATIONAL_CADASTRAL_REFERENCE",
      "NR_CAD",
      "AREA_VALUE",
      "NR_CF",
      "NR_CF_VECHI",
      "NR_TOPO",
      "ADRESA",
      "PROPRIETARI",
      "PROPRIETARI_VECHI",
      "SUPRAFATA_2D",
      "SUPRAFATA_R",
      "SOLICITANT",
      "INTRAVILAN",
      "CATEGORIE_FOLOSINTA",
      "HAS_BUILDING",
      "BUILD_LEGAL",
      "HAS_GEOMETRY",
    ];
    const csvRows: string[] = [headers.map(csvEscape).join(",")];

    const magicFeatures: GeoJsonFeature[] = [];
    const magicFields = Array.from(
      new Set([
        ...terenuriFields,
        "NR_CAD",
        "NR_CF",
        "NR_CF_VECHI",
        "NR_TOPO",
        "ADRESA",
        "PROPRIETARI",
        "PROPRIETARI_VECHI",
        "SUPRAFATA_2D",
        "SUPRAFATA_R",
        "SOLICITANT",
        "INTRAVILAN",
        "CATEGORIE_FOLOSINTA",
        "HAS_BUILDING",
        "BUILD_LEGAL",
      ]),
    );

    let hasBuildingCount = 0;
    let legalBuildingCount = 0;

    for (const record of dbTerenuri) {
      const attrs = record.attributes as Record<string, unknown>;
      const enrichment =
        (record.enrichment as FeatureEnrichment | null) ??
        ({} as Partial<FeatureEnrichment>);
      const geom = record.geometry as GeoJsonFeature["geometry"];
      const geomSource = (
        record as unknown as { geometrySource: string | null }
      ).geometrySource;
      const hasGeometry = geom != null && geomSource !== "NO_GEOMETRY" ? 1 : 0;

      const e = enrichment as Partial<FeatureEnrichment>;
      if (Number(e.HAS_BUILDING ?? 0)) hasBuildingCount += 1;
      if (Number(e.BUILD_LEGAL ?? 0)) legalBuildingCount += 1;

      csvRows.push(
        [
          attrs.OBJECTID ?? "",
          attrs.IMMOVABLE_ID ?? "",
          attrs.APPLICATION_ID ?? "",
          attrs.NATIONAL_CADASTRAL_REFERENCE ?? "",
          e.NR_CAD ?? "",
          attrs.AREA_VALUE ?? "",
          e.NR_CF ?? "",
          e.NR_CF_VECHI ?? "",
          e.NR_TOPO ?? "",
          e.ADRESA ?? "",
          e.PROPRIETARI ?? "",
          e.PROPRIETARI_VECHI ?? "",
          e.SUPRAFATA_2D ?? "",
          e.SUPRAFATA_R ?? "",
          e.SOLICITANT ?? "",
          e.INTRAVILAN ?? "",
          e.CATEGORIE_FOLOSINTA ?? "",
          e.HAS_BUILDING ?? 0,
          e.BUILD_LEGAL ?? 0,
          hasGeometry,
        ]
          .map(csvEscape)
          .join(","),
      );

      magicFeatures.push({
        type: "Feature",
        geometry: geom,
        properties: { ...attrs, ...e, HAS_GEOMETRY: hasGeometry },
      });
    }

    const magicGpkg = await buildGpkg({
      srsId: 3844,
      srsWkt,
      layers: [
        {
          name: "TERENURI_MAGIC",
          fields: [...magicFields, "HAS_GEOMETRY"],
          features: magicFeatures,
          includeNullGeometry: true,
        },
      ],
    });

    zip.file("terenuri_magic.gpkg", magicGpkg);
    const magicDxf = await gpkgToDxf(magicGpkg, "TERENURI_MAGIC");
    if (magicDxf) zip.file("terenuri_magic.dxf", magicDxf);
    zip.file("terenuri_complet.csv", csvRows.join("\n"));

    // ── Quality analysis ──
    const withGeomRecords = dbTerenuri.filter(
      (r) =>
        (r as unknown as { geometrySource: string | null }).geometrySource !==
        "NO_GEOMETRY",
    );
    const noGeomRecords = dbTerenuri.filter(
      (r) =>
        (r as unknown as { geometrySource: string | null }).geometrySource ===
        "NO_GEOMETRY",
    );

    const analyzeRecords = (records: typeof dbTerenuri) => {
      let enriched = 0,
        withOwners = 0,
        withOldOwners = 0,
        withCF = 0;
      let withAddress = 0,
        withArea = 0,
        withCategory = 0,
        withBuilding = 0;
      let complete = 0,
        partial = 0,
        empty = 0;
      for (const r of records) {
        const en = r.enrichment as Record<string, unknown> | null;
        if (!en) {
          empty++;
          continue;
        }
        enriched++;
        const ho = !!en.PROPRIETARI && en.PROPRIETARI !== "-";
        const hoo =
          !!en.PROPRIETARI_VECHI && String(en.PROPRIETARI_VECHI).trim() !== "";
        const hc = !!en.NR_CF && en.NR_CF !== "-";
        const ha = !!en.ADRESA && en.ADRESA !== "-";
        const harea =
          en.SUPRAFATA_2D != null &&
          en.SUPRAFATA_2D !== "" &&
          Number(en.SUPRAFATA_2D) > 0;
        const hcat = !!en.CATEGORIE_FOLOSINTA && en.CATEGORIE_FOLOSINTA !== "-";
        const hb = Number(en.HAS_BUILDING ?? 0) === 1;
        if (ho) withOwners++;
        if (hoo) withOldOwners++;
        if (hc) withCF++;
        if (ha) withAddress++;
        if (harea) withArea++;
        if (hcat) withCategory++;
        if (hb) withBuilding++;
        if (ho && hc && harea) complete++;
        else if (ho || hc || ha || harea || hcat) partial++;
        else empty++;
      }
      return {
        total: records.length,
        enriched,
        withOwners,
        withOldOwners,
        withCF,
        withAddress,
        withArea,
        withCategory,
        withBuilding,
        complete,
        partial,
        empty,
      };
    };

    const qAll = analyzeRecords(dbTerenuri);
    const qGeo = analyzeRecords(withGeomRecords);
    const qNoGeo = analyzeRecords(noGeomRecords);

    // Quality report
    const pct = (n: number, t: number) =>
      t > 0 ? `${((n / t) * 100).toFixed(1)}%` : "0%";
    const fmt = (n: number) => n.toLocaleString("ro-RO");
    const lines: string[] = [
      `══════════════════════════════════════════════════════════`,
      `  RAPORT CALITATE DATE — UAT SIRUTA ${siruta}`,
      `  Generat: ${new Date().toISOString().replace("T", " ").slice(0, 19)}`,
      `  Sursă: bază de date locală (fără conexiune eTerra)`,
      `══════════════════════════════════════════════════════════`,
      ``,
      `STARE BAZĂ DE DATE`,
      `─────────────────────────────────────────────────────────`,
      `  Total parcele:                    ${fmt(dbTerenuri.length)}`,
      `    • Cu geometrie (contur GIS):    ${fmt(withGeomRecords.length)}`,
      `    • Fără geometrie (doar date):   ${fmt(noGeomRecords.length)}`,
      `  Clădiri:                          ${fmt(cladiriGeo.length)}`,
      ``,
      `CALITATE ÎMBOGĂȚIRE — TOATE PARCELELE (${fmt(qAll.total)})`,
      `─────────────────────────────────────────────────────────`,
      `  Îmbogățite:        ${fmt(qAll.enriched)} (${pct(qAll.enriched, qAll.total)})`,
      `  Cu proprietari:    ${fmt(qAll.withOwners)} (${pct(qAll.withOwners, qAll.total)})`,
      `  Cu prop. vechi:    ${fmt(qAll.withOldOwners)} (${pct(qAll.withOldOwners, qAll.total)})`,
      `  Cu nr. CF:         ${fmt(qAll.withCF)} (${pct(qAll.withCF, qAll.total)})`,
      `  Cu adresă:         ${fmt(qAll.withAddress)} (${pct(qAll.withAddress, qAll.total)})`,
      `  Cu suprafață:      ${fmt(qAll.withArea)} (${pct(qAll.withArea, qAll.total)})`,
      `  Cu categorie fol.: ${fmt(qAll.withCategory)} (${pct(qAll.withCategory, qAll.total)})`,
      `  Cu clădire:        ${fmt(qAll.withBuilding)} (${pct(qAll.withBuilding, qAll.total)})`,
      `  ────────────────`,
      `  Complete (prop+CF+sup): ${fmt(qAll.complete)} (${pct(qAll.complete, qAll.total)})`,
      `  Parțiale:              ${fmt(qAll.partial)} (${pct(qAll.partial, qAll.total)})`,
      `  Goale (fără date):     ${fmt(qAll.empty)} (${pct(qAll.empty, qAll.total)})`,
      ``,
    ];

    if (withGeomRecords.length > 0) {
      lines.push(
        `PARCELE CU GEOMETRIE (${fmt(qGeo.total)})`,
        `─────────────────────────────────────────────────────────`,
        `  Complete: ${fmt(qGeo.complete)}  Parțiale: ${fmt(qGeo.partial)}  Goale: ${fmt(qGeo.empty)}`,
        ``,
      );
    }
    if (noGeomRecords.length > 0) {
      lines.push(
        `PARCELE FĂRĂ GEOMETRIE (${fmt(qNoGeo.total)})`,
        `─────────────────────────────────────────────────────────`,
        `  Complete: ${fmt(qNoGeo.complete)}  Parțiale: ${fmt(qNoGeo.partial)}  Goale: ${fmt(qNoGeo.empty)}`,
        ``,
      );
    }
    lines.push(
      `NOTE`,
      `─────────────────────────────────────────────────────────`,
      `  • Export din baza de date locală — fără conexiune eTerra`,
      `  • "Complete" = are proprietari + nr. CF + suprafață`,
      `══════════════════════════════════════════════════════════`,
    );
    zip.file("raport_calitate.txt", lines.join("\n"));

    const report = {
      siruta,
      generatedAt: new Date().toISOString(),
      source: "local-db (descărcare din DB)",
      terenuri: {
        total: dbTerenuri.length,
        withGeom: withGeomRecords.length,
        noGeom: noGeomRecords.length,
      },
      cladiri: { count: cladiriGeo.length },
      magic: {
        csvRows: csvRows.length - 1,
        hasBuildingCount,
        legalBuildingCount,
      },
      quality: { all: qAll, withGeom: qGeo, noGeom: qNoGeo },
    };
    zip.file("export_report.json", JSON.stringify(report, null, 2));
  }

  const zipBuf = await zip.generateAsync({
    type: "nodebuffer",
    compression: "STORE",
  });
  const filename =
    mode === "magic"
      ? `eterra_uat_${siruta}_magic_local.zip`
      : `eterra_uat_${siruta}_local.zip`;

  return new Response(new Uint8Array(zipBuf), {
    headers: {
      "Content-Type": "application/zip",
      "Content-Disposition": `attachment; filename="${filename}"`,
    },
  });
}

/* ────────────────────────────────────────────────────────── */
/*  Layer GPKG builder                                         */
/* ────────────────────────────────────────────────────────── */

async function buildLayerGpkg(siruta: string, layerId: string) {
  const features = await prisma.gisFeature.findMany({
    where: { layerId, siruta },
    select: { attributes: true, geometry: true },
  });

  if (features.length === 0) {
    throw new Error(`Niciun feature local pentru ${layerId} / ${siruta}`);
  }

  const geoFeatures: GeoJsonFeature[] = features
    .filter((f) => f.geometry != null)
    .map((f) => ({
      type: "Feature" as const,
      geometry: f.geometry as GeoJsonFeature["geometry"],
      properties: f.attributes as Record<string, unknown>,
    }));

  const fields = Object.keys(geoFeatures[0]?.properties ?? {});
  const layer = findLayerById(layerId);
  const name = layer?.name ?? layerId;

  return buildGpkg({
    srsId: 3844,
    srsWkt: getEpsg3844Wkt(),
    layers: [{ name, fields, features: geoFeatures }],
  });
}
