/**
 * GET /api/eterra/tiles/orto?z=...&x=...&y=...
 *
 * Proxies eTerra ORTO2024 ortophoto tiles. Converts Web Mercator
 * tile coordinates to EPSG:3844 bbox and fetches from eTerra exportImage.
 * Requires active eTerra session (uses stored credentials).
 */
import { NextResponse } from "next/server";
import proj4 from "proj4";

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

// Register projections
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";
proj4.defs("EPSG:3844", EPSG_3844_DEF);
proj4.defs("EPSG:4326", "+proj=longlat +datum=WGS84 +no_defs");

const TILE_SIZE = 512;
const ETERRA_BASE = "https://eterra.ancpi.ro/eterra";
const ORTO_ENDPOINT = `${ETERRA_BASE}/api/map/rest/basemap/ORTO2024/exportImage`;

/** Convert tile z/x/y to WGS84 bounding box [west, south, east, north] */
function tileToBbox(z: number, x: number, y: number): [number, number, number, number] {
  const n = Math.pow(2, z);
  const lonW = (x / n) * 360 - 180;
  const lonE = ((x + 1) / n) * 360 - 180;
  const latN = (Math.atan(Math.sinh(Math.PI * (1 - (2 * y) / n))) * 180) / Math.PI;
  const latS = (Math.atan(Math.sinh(Math.PI * (1 - (2 * (y + 1)) / n))) * 180) / Math.PI;
  return [lonW, latS, lonE, latN];
}

/** Reproject WGS84 bbox to EPSG:3844 using all 4 corners (handles projection curvature) */
function bboxTo3844(bbox4326: [number, number, number, number]): [number, number, number, number] {
  const [w, s, e, n] = bbox4326;
  // Project all 4 corners to handle non-linear projection
  const corners = [
    proj4("EPSG:4326", "EPSG:3844", [w, s]),
    proj4("EPSG:4326", "EPSG:3844", [e, s]),
    proj4("EPSG:4326", "EPSG:3844", [w, n]),
    proj4("EPSG:4326", "EPSG:3844", [e, n]),
  ];
  const xs = corners.map((c) => c[0]!);
  const ys = corners.map((c) => c[1]!);
  return [Math.min(...xs), Math.min(...ys), Math.max(...xs), Math.max(...ys)];
}

// Simple in-memory cookie cache for eTerra session
let cachedCookie: string | null = null;
let cookieExpiry = 0;

async function getEterraCookie(): Promise<string | null> {
  if (cachedCookie && Date.now() < cookieExpiry) return cachedCookie;

  const username = process.env.ETERRA_USERNAME;
  const password = process.env.ETERRA_PASSWORD;
  if (!username || !password) return null;

  try {
    const loginUrl = `${ETERRA_BASE}/api/authentication`;
    const body = new URLSearchParams({
      j_username: username,
      j_password: password,
      j_uuid: "undefined",
      j_isRevoked: "undefined",
      _spring_security_remember_me: "true",
      submit: "Login",
    });

    const resp = await fetch(loginUrl, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: body.toString(),
      redirect: "manual",
    });

    const setCookies = resp.headers.getSetCookie?.() ?? [];
    const jsessionId = setCookies
      .find((c) => c.startsWith("JSESSIONID="))
      ?.split(";")[0];

    if (jsessionId) {
      cachedCookie = jsessionId;
      cookieExpiry = Date.now() + 8 * 60 * 1000; // 8 min TTL
      return cachedCookie;
    }
    return null;
  } catch {
    return null;
  }
}

export async function GET(req: Request) {
  try {
    const url = new URL(req.url);
    const z = parseInt(url.searchParams.get("z") ?? "", 10);
    const x = parseInt(url.searchParams.get("x") ?? "", 10);
    const y = parseInt(url.searchParams.get("y") ?? "", 10);

    if (isNaN(z) || isNaN(x) || isNaN(y)) {
      return NextResponse.json({ error: "z, x, y required" }, { status: 400 });
    }

    // Only serve tiles within Romania's approximate bounds (zoom >= 6)
    if (z < 6) {
      return new Response(null, { status: 204 });
    }

    const bbox4326 = tileToBbox(z, x, y);
    const bbox3844 = bboxTo3844(bbox4326);

    const cookie = await getEterraCookie();
    if (!cookie) {
      return NextResponse.json(
        { error: "eTerra login esuat - verificati credentialele" },
        { status: 401 }
      );
    }

    const params = new URLSearchParams({
      f: "image",
      bbox: bbox3844.join(","),
      imageSR: "3844",
      bboxSR: "3844",
      size: `${TILE_SIZE},${TILE_SIZE}`,
    });

    const imageResp = await fetch(`${ORTO_ENDPOINT}?${params}`, {
      headers: { Cookie: cookie },
      signal: AbortSignal.timeout(15_000),
    });

    if (!imageResp.ok) {
      // Return transparent tile for areas without coverage
      return new Response(null, { status: 204 });
    }

    const imageBuffer = await imageResp.arrayBuffer();

    return new Response(imageBuffer, {
      headers: {
        "Content-Type": "image/png",
        "Cache-Control": "public, max-age=86400", // cache 24h
      },
    });
  } catch {
    return new Response(null, { status: 204 });
  }
}
