import { NextResponse } from "next/server";
import { prisma } from "@/core/storage/prisma";

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

/* ------------------------------------------------------------------ */
/*  Types                                                              */
/* ------------------------------------------------------------------ */

export type UatDashboardData = {
  siruta: string;
  uatName: string;
  county: string;

  /* ── Counts ────────────────────────────── */
  totalTerenuri: number;
  totalCladiri: number;
  totalNoGeom: number;
  totalEnriched: number;
  enrichmentPct: number; // 0-100

  /* ── Area ──────────────────────────────── */
  totalAreaHa: number; // total area in hectares
  avgAreaMp: number;
  medianAreaMp: number;
  areaDistribution: { bucket: string; count: number; pct: number }[];

  /* ── Intravilan ────────────────────────── */
  intravilanCount: number;
  extravilanCount: number;
  mixtCount: number;
  intravilanPct: number;

  /* ── Buildings ─────────────────────────── */
  withBuildingCount: number;
  buildingLegalCount: number;
  withBuildingPct: number;

  /* ── Ownership ─────────────────────────── */
  uniqueOwnerCount: number;
  topOwners: { name: string; count: number }[];
  parcelsWithoutCF: number;
  parcelsWithoutCFPct: number;

  /* ── Land use (categorie folosinta) ────── */
  landUseDistribution: {
    category: string;
    count: number;
    areaMp: number;
    pct: number;
  }[];

  /* ── Sync ──────────────────────────────── */
  lastSyncDate: string | null;
  syncRunCount: number;

  /* ── Fun facts ─────────────────────────── */
  funFacts: string[];
};

/* ------------------------------------------------------------------ */
/*  GET /api/eterra/uat-dashboard?siruta=XXXX                          */
/* ------------------------------------------------------------------ */

export async function GET(req: Request) {
  try {
    const url = new URL(req.url);
    const siruta = url.searchParams.get("siruta")?.trim();

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

    // ── UAT info ──
    const uat = await prisma.gisUat.findUnique({ where: { siruta } });
    const uatName = uat?.name ?? siruta;
    const county = uat?.county ?? "";

    // ── Basic counts ──
    const [terenuriCount, cladiriCount, noGeomCount, enrichedCount] =
      await Promise.all([
        prisma.gisFeature.count({
          where: { siruta, layerId: "TERENURI_ACTIVE" },
        }),
        prisma.gisFeature.count({
          where: { siruta, layerId: "CLADIRI_ACTIVE" },
        }),
        prisma.gisFeature.count({
          where: { siruta, geometrySource: "NO_GEOMETRY" },
        }),
        prisma.gisFeature.count({
          where: { siruta, enrichedAt: { not: null } },
        }),
      ]);

    const totalTerenuri = terenuriCount;
    if (totalTerenuri === 0) {
      return NextResponse.json({
        error: "Nicio parcelă pentru acest UAT.",
      });
    }
    const enrichmentPct = Math.round((enrichedCount / totalTerenuri) * 100);

    // ── Area stats (from enrichment or areaValue) ──
    const areaStats = await prisma.$queryRaw<
      [{ total_area: number | null; avg_area: number | null; cnt: number }]
    >`
      SELECT
        COALESCE(SUM("areaValue"), 0)::float AS total_area,
        COALESCE(AVG("areaValue"), 0)::float AS avg_area,
        COUNT(*)::int AS cnt
      FROM "GisFeature"
      WHERE siruta = ${siruta}
        AND "layerId" = 'TERENURI_ACTIVE'
        AND "areaValue" IS NOT NULL
        AND "areaValue" > 0
    `;
    const totalAreaMp = areaStats[0]?.total_area ?? 0;
    const totalAreaHa = Math.round((totalAreaMp / 10000) * 100) / 100;
    const avgAreaMp = Math.round(areaStats[0]?.avg_area ?? 0);

    // Median area
    const medianResult = await prisma.$queryRaw<[{ median: number | null }]>`
      SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY "areaValue")::float AS median
      FROM "GisFeature"
      WHERE siruta = ${siruta}
        AND "layerId" = 'TERENURI_ACTIVE'
        AND "areaValue" IS NOT NULL
        AND "areaValue" > 0
    `;
    const medianAreaMp = Math.round(medianResult[0]?.median ?? 0);

    // Area distribution buckets
    const areaBuckets = await prisma.$queryRaw<
      Array<{ bucket: string; count: number }>
    >`
      SELECT
        CASE
          WHEN "areaValue" <= 100 THEN '0-100'
          WHEN "areaValue" <= 500 THEN '100-500'
          WHEN "areaValue" <= 1000 THEN '500-1.000'
          WHEN "areaValue" <= 2500 THEN '1.000-2.500'
          WHEN "areaValue" <= 5000 THEN '2.500-5.000'
          WHEN "areaValue" <= 10000 THEN '5.000-10.000'
          ELSE '10.000+'
        END AS bucket,
        COUNT(*)::int AS count
      FROM "GisFeature"
      WHERE siruta = ${siruta}
        AND "layerId" = 'TERENURI_ACTIVE'
        AND "areaValue" IS NOT NULL
        AND "areaValue" > 0
      GROUP BY bucket
      ORDER BY MIN("areaValue")
    `;
    const totalWithArea = areaBuckets.reduce((s, b) => s + b.count, 0) || 1;
    const areaDistribution = areaBuckets.map((b) => ({
      bucket: b.bucket,
      count: b.count,
      pct: Math.round((b.count / totalWithArea) * 100),
    }));

    // ── Intravilan/Extravilan (from enrichment) ──
    const intravilanStats = await prisma.$queryRaw<
      Array<{ val: string; count: number }>
    >`
      SELECT
        COALESCE(enrichment->>'INTRAVILAN', '-') AS val,
        COUNT(*)::int AS count
      FROM "GisFeature"
      WHERE siruta = ${siruta}
        AND "layerId" = 'TERENURI_ACTIVE'
        AND enrichment IS NOT NULL
      GROUP BY val
    `;
    let intravilanCount = 0;
    let extravilanCount = 0;
    let mixtCount = 0;
    for (const row of intravilanStats) {
      if (row.val === "Da") intravilanCount = row.count;
      else if (row.val === "Nu") extravilanCount = row.count;
      else if (row.val === "Mixt") mixtCount = row.count;
    }
    const totalIntraBase = intravilanCount + extravilanCount + mixtCount || 1;
    const intravilanPct = Math.round((intravilanCount / totalIntraBase) * 100);

    // ── Buildings (from enrichment) ──
    const buildingStats = await prisma.$queryRaw<
      [{ with_building: number; legal_building: number }]
    >`
      SELECT
        COUNT(*) FILTER (WHERE (enrichment->>'HAS_BUILDING')::int = 1)::int AS with_building,
        COUNT(*) FILTER (WHERE (enrichment->>'BUILD_LEGAL')::int = 1)::int AS legal_building
      FROM "GisFeature"
      WHERE siruta = ${siruta}
        AND "layerId" = 'TERENURI_ACTIVE'
        AND enrichment IS NOT NULL
    `;
    const withBuildingCount = buildingStats[0]?.with_building ?? 0;
    const buildingLegalCount = buildingStats[0]?.legal_building ?? 0;
    const withBuildingPct =
      enrichedCount > 0
        ? Math.round((withBuildingCount / enrichedCount) * 100)
        : 0;

    // ── Land use categories (from enrichment) ──
    // enrichment CATEGORIE_FOLOSINTA looks like "Arabil:2500.00; Pășune:1200.00"
    const landUseRaw = await prisma.$queryRaw<Array<{ cat: string }>>`
      SELECT enrichment->>'CATEGORIE_FOLOSINTA' AS cat
      FROM "GisFeature"
      WHERE siruta = ${siruta}
        AND "layerId" = 'TERENURI_ACTIVE'
        AND enrichment IS NOT NULL
        AND enrichment->>'CATEGORIE_FOLOSINTA' IS NOT NULL
        AND enrichment->>'CATEGORIE_FOLOSINTA' != ''
        AND enrichment->>'CATEGORIE_FOLOSINTA' != '-'
    `;
    const landUseMap = new Map<string, { count: number; area: number }>();
    for (const row of landUseRaw) {
      // Parse "Arabil:2500.00; Pășune:1200.00" format
      const parts = (row.cat ?? "").split(";").map((s) => s.trim());
      for (const part of parts) {
        const [name, areaStr] = part.split(":");
        if (!name) continue;
        const key = name.trim();
        const area = parseFloat(areaStr ?? "0") || 0;
        const existing = landUseMap.get(key) ?? { count: 0, area: 0 };
        existing.count += 1;
        existing.area += area;
        landUseMap.set(key, existing);
      }
    }
    const totalLandUseCount =
      Array.from(landUseMap.values()).reduce((s, v) => s + v.count, 0) || 1;
    const landUseDistribution = Array.from(landUseMap.entries())
      .sort((a, b) => b[1].count - a[1].count)
      .slice(0, 15)
      .map(([category, data]) => ({
        category,
        count: data.count,
        areaMp: Math.round(data.area),
        pct: Math.round((data.count / totalLandUseCount) * 100),
      }));

    // ── Ownership stats (from enrichment) ──
    const ownerRaw = await prisma.$queryRaw<Array<{ owners: string }>>`
      SELECT enrichment->>'PROPRIETARI' AS owners
      FROM "GisFeature"
      WHERE siruta = ${siruta}
        AND "layerId" = 'TERENURI_ACTIVE'
        AND enrichment IS NOT NULL
        AND enrichment->>'PROPRIETARI' IS NOT NULL
        AND enrichment->>'PROPRIETARI' != ''
        AND enrichment->>'PROPRIETARI' != '-'
    `;
    const ownerCountMap = new Map<string, number>();
    for (const row of ownerRaw) {
      const names = (row.owners ?? "")
        .split(";")
        .map((n) => n.trim())
        .filter(Boolean);
      for (const name of names) {
        ownerCountMap.set(name, (ownerCountMap.get(name) ?? 0) + 1);
      }
    }
    const uniqueOwnerCount = ownerCountMap.size;
    const topOwners = Array.from(ownerCountMap.entries())
      .sort((a, b) => b[1] - a[1])
      .slice(0, 10)
      .map(([name, count]) => ({ name, count }));

    // Parcels without CF
    const noCFResult = await prisma.$queryRaw<[{ count: number }]>`
      SELECT COUNT(*)::int AS count
      FROM "GisFeature"
      WHERE siruta = ${siruta}
        AND "layerId" = 'TERENURI_ACTIVE'
        AND enrichment IS NOT NULL
        AND (
          enrichment->>'NR_CF' IS NULL
          OR enrichment->>'NR_CF' = ''
          OR enrichment->>'NR_CF' = '-'
        )
    `;
    const parcelsWithoutCF = noCFResult[0]?.count ?? 0;
    const parcelsWithoutCFPct =
      enrichedCount > 0
        ? Math.round((parcelsWithoutCF / enrichedCount) * 100)
        : 0;

    // ── Sync runs ──
    const syncRuns = await prisma.gisSyncRun.findMany({
      where: { siruta },
      orderBy: { startedAt: "desc" },
      take: 1,
      select: { startedAt: true },
    });
    const syncRunCount = await prisma.gisSyncRun.count({
      where: { siruta },
    });
    const lastSyncDate = syncRuns[0]?.startedAt?.toISOString() ?? null;

    // ── Fun facts ──
    const funFacts: string[] = [];

    // Largest parcel
    const largestParcel = await prisma.$queryRaw<
      [{ cad: string | null; area: number | null }]
    >`
      SELECT "cadastralRef" AS cad, "areaValue" AS area
      FROM "GisFeature"
      WHERE siruta = ${siruta}
        AND "layerId" = 'TERENURI_ACTIVE'
        AND "areaValue" IS NOT NULL
      ORDER BY "areaValue" DESC
      LIMIT 1
    `;
    if (largestParcel[0]?.area) {
      const aHa = (largestParcel[0].area / 10000).toFixed(2);
      funFacts.push(
        `Cea mai mare parcelă: ${largestParcel[0].cad ?? "?"} — ${aHa} ha (${Math.round(largestParcel[0].area).toLocaleString("ro-RO")} mp)`,
      );
    }

    // Smallest parcel
    const smallestParcel = await prisma.$queryRaw<
      [{ cad: string | null; area: number | null }]
    >`
      SELECT "cadastralRef" AS cad, "areaValue" AS area
      FROM "GisFeature"
      WHERE siruta = ${siruta}
        AND "layerId" = 'TERENURI_ACTIVE'
        AND "areaValue" IS NOT NULL
        AND "areaValue" > 0
      ORDER BY "areaValue" ASC
      LIMIT 1
    `;
    if (smallestParcel[0]?.area) {
      funFacts.push(
        `Cea mai mică parcelă: ${smallestParcel[0].cad ?? "?"} — ${Math.round(smallestParcel[0].area).toLocaleString("ro-RO")} mp`,
      );
    }

    // Owner with most parcels
    const topOwner = topOwners[0];
    if (topOwner) {
      funFacts.push(
        `Cel mai mare proprietar: ${topOwner.name} — ${topOwner.count} parcele`,
      );
    }

    // Intravilan ratio insight
    if (intravilanPct > 70) {
      funFacts.push(`UAT predominant intravilan (${intravilanPct}%)`);
    } else if (intravilanPct < 30 && enrichedCount > 0) {
      funFacts.push(
        `UAT predominant extravilan (doar ${intravilanPct}% intravilan)`,
      );
    }

    // Building density
    if (withBuildingPct > 50) {
      funFacts.push(
        `Densitate ridicată de clădiri: ${withBuildingPct}% din parcele au construcții`,
      );
    }

    // Coverage gap
    if (noGeomCount > 0) {
      const pct = Math.round(
        (noGeomCount / (totalTerenuri + noGeomCount)) * 100,
      );
      funFacts.push(
        `${pct}% din imobile nu au geometrie GIS (${noGeomCount.toLocaleString("ro-RO")} fără geom)`,
      );
    }

    const result: UatDashboardData = {
      siruta,
      uatName,
      county,
      totalTerenuri,
      totalCladiri: cladiriCount,
      totalNoGeom: noGeomCount,
      totalEnriched: enrichedCount,
      enrichmentPct,
      totalAreaHa,
      avgAreaMp,
      medianAreaMp,
      areaDistribution,
      intravilanCount,
      extravilanCount,
      mixtCount,
      intravilanPct,
      withBuildingCount,
      buildingLegalCount,
      withBuildingPct,
      uniqueOwnerCount,
      topOwners,
      parcelsWithoutCF,
      parcelsWithoutCFPct,
      landUseDistribution,
      lastSyncDate,
      syncRunCount,
      funFacts,
    };

    return NextResponse.json(result);
  } catch (error) {
    const message = error instanceof Error ? error.message : "Eroare server";
    console.error("[uat-dashboard]", message);
    return NextResponse.json({ error: message }, { status: 500 });
  }
}
