/**
 * POST /api/geoportal/export
 *
 * Exports selected GIS features as GeoJSON, DXF, or GeoPackage.
 * Body: { ids: string[], format: "geojson" | "dxf" | "gpkg" }
 *
 * - GeoJSON: always works (pure JS)
 * - DXF/GPKG: requires ogr2ogr (available in Docker image via gdal-tools)
 */
import { NextResponse } from "next/server";
import { Prisma } from "@prisma/client";
import { prisma } from "@/core/storage/prisma";
import { writeFile, readFile, unlink, mkdtemp } from "fs/promises";
import { tmpdir } from "os";
import { join } from "path";
import { execFile } from "child_process";
import { promisify } from "util";

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

const execFileAsync = promisify(execFile);

type ExportRequest = {
  ids: string[];
  format: "geojson" | "dxf" | "gpkg";
};

export async function POST(req: Request) {
  let tmpDir: string | null = null;

  try {
    const body = (await req.json()) as ExportRequest;
    const { ids, format } = body;

    if (!Array.isArray(ids) || ids.length === 0) {
      return NextResponse.json(
        { error: "Selecteaza cel putin o parcela" },
        { status: 400 }
      );
    }

    if (!["geojson", "dxf", "gpkg"].includes(format)) {
      return NextResponse.json(
        { error: "Format invalid. Optiuni: geojson, dxf, gpkg" },
        { status: 400 }
      );
    }

    // The IDs from the selection are objectId strings
    // Query features by objectId (converted to int)
    const objectIds = ids.map((id) => parseInt(id, 10)).filter((n) => !isNaN(n));

    if (objectIds.length === 0) {
      return NextResponse.json(
        { error: "Niciun ID valid in selectie" },
        { status: 400 }
      );
    }

    const features = await prisma.gisFeature.findMany({
      where: {
        objectId: { in: objectIds },
        geometry: { not: Prisma.JsonNull },
      },
      select: {
        objectId: true,
        cadastralRef: true,
        areaValue: true,
        attributes: true,
        geometry: true,
        enrichment: true,
        layerId: true,
        siruta: true,
      },
    });

    if (features.length === 0) {
      return NextResponse.json(
        { error: "Niciun feature cu geometrie gasit" },
        { status: 404 }
      );
    }

    // Build GeoJSON FeatureCollection
    const geojson = {
      type: "FeatureCollection" as const,
      crs: {
        type: "name",
        properties: { name: "urn:ogc:def:crs:EPSG::3844" },
      },
      features: features.map((f) => {
        const enrichment = (f.enrichment ?? {}) as Record<string, unknown>;
        return {
          type: "Feature" as const,
          geometry: f.geometry as Record<string, unknown>,
          properties: {
            objectId: f.objectId,
            cadastralRef: f.cadastralRef,
            areaValue: f.areaValue,
            layerId: f.layerId,
            siruta: f.siruta,
            NR_CAD: enrichment.NR_CAD ?? "",
            NR_CF: enrichment.NR_CF ?? "",
            PROPRIETARI: enrichment.PROPRIETARI ?? "",
            SUPRAFATA: enrichment.SUPRAFATA_2D ?? "",
            INTRAVILAN: enrichment.INTRAVILAN ?? "",
            CATEGORIE: enrichment.CATEGORIE_FOLOSINTA ?? "",
          },
        };
      }),
    };

    const timestamp = new Date().toISOString().slice(0, 10);

    // GeoJSON — return directly
    if (format === "geojson") {
      const filename = `parcele_${timestamp}.geojson`;
      return new Response(JSON.stringify(geojson, null, 2), {
        headers: {
          "Content-Type": "application/geo+json",
          "Content-Disposition": `attachment; filename="${filename}"`,
        },
      });
    }

    // DXF or GPKG — use ogr2ogr
    tmpDir = await mkdtemp(join(tmpdir(), "geoportal-export-"));
    const inputPath = join(tmpDir, "input.geojson");
    await writeFile(inputPath, JSON.stringify(geojson));

    const ext = format === "dxf" ? "dxf" : "gpkg";
    const outputPath = join(tmpDir, `output.${ext}`);
    const ogrFormat = format === "dxf" ? "DXF" : "GPKG";

    // DXF: reproject to WGS84 (-s_srs + -t_srs). GPKG: assign CRS only (-a_srs).
    const ogrArgs = format === "dxf"
      ? ["-f", ogrFormat, outputPath, inputPath, "-s_srs", "EPSG:3844", "-t_srs", "EPSG:4326"]
      : ["-f", ogrFormat, outputPath, inputPath, "-a_srs", "EPSG:3844"];

    try {
      await execFileAsync("ogr2ogr", ogrArgs, { timeout: 30_000 });
    } catch (err: unknown) {
      const errMsg = err instanceof Error ? err.message : String(err);
      // ogr2ogr not available (local dev without GDAL)
      if (errMsg.includes("ENOENT") || errMsg.includes("not found")) {
        return NextResponse.json(
          { error: `Export ${format.toUpperCase()} disponibil doar in productie (Docker cu GDAL)` },
          { status: 501 }
        );
      }
      return NextResponse.json(
        { error: `ogr2ogr a esuat: ${errMsg}` },
        { status: 500 }
      );
    }

    const outputBuffer = await readFile(outputPath);
    const filename = `parcele_${timestamp}.${ext}`;

    const contentType =
      format === "dxf"
        ? "application/dxf"
        : "application/geopackage+sqlite3";

    // Clean up temp files (best effort)
    cleanup(tmpDir);
    tmpDir = null;

    return new Response(outputBuffer, {
      headers: {
        "Content-Type": contentType,
        "Content-Disposition": `attachment; filename="${filename}"`,
      },
    });
  } catch (error) {
    if (tmpDir) cleanup(tmpDir);
    const msg = error instanceof Error ? error.message : "Eroare la export";
    return NextResponse.json({ error: msg }, { status: 500 });
  }
}

async function cleanup(dir: string) {
  try {
    const { readdir } = await import("fs/promises");
    const files = await readdir(dir);
    for (const f of files) {
      await unlink(join(dir, f)).catch(() => {});
    }
    const { rmdir } = await import("fs/promises");
    await rmdir(dir).catch(() => {});
  } catch {
    // best effort
  }
}
