import { NextResponse } from "next/server";
import { PrismaClient } from "@prisma/client";
import { syncLayer } from "@/modules/parcel-sync/services/sync-service";
import {
  getLayerFreshness,
  isFresh,
} from "@/modules/parcel-sync/services/enrich-service";
import { checkEterraHealthNow } from "@/modules/parcel-sync/services/eterra-health";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";
export const maxDuration = 300; // 5 min max — N8N handles overall timeout

const prisma = new PrismaClient();

const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

type UatRefreshResult = {
  siruta: string;
  uatName: string;
  action: "synced" | "fresh" | "error";
  reason?: string;
  terenuri?: { new: number; removed: number };
  cladiri?: { new: number; removed: number };
  durationMs?: number;
};

/**
 * POST /api/eterra/auto-refresh
 *
 * Server-to-server endpoint called by N8N cron to keep DB data fresh.
 * Auth: Authorization: Bearer <NOTIFICATION_CRON_SECRET>
 *
 * Query params:
 *   ?maxUats=5          — max UATs to process per run (default 5, max 10)
 *   ?maxAgeHours=168    — freshness threshold in hours (default 168 = 7 days)
 *   ?forceFullSync=true — force full re-download (for weekly deep sync)
 *   ?includeEnrichment=true — re-enrich UATs with partial enrichment
 */
export async function POST(request: Request) {
  // ── Auth ──
  const secret = process.env.NOTIFICATION_CRON_SECRET;
  if (!secret) {
    return NextResponse.json(
      { error: "NOTIFICATION_CRON_SECRET not configured" },
      { status: 500 },
    );
  }
  const authHeader = request.headers.get("Authorization");
  const token = authHeader?.replace("Bearer ", "");
  if (token !== secret) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  // ── Parse params ──
  const url = new URL(request.url);
  const maxUats = Math.min(
    Number(url.searchParams.get("maxUats") ?? "5") || 5,
    10,
  );
  const maxAgeHours =
    Number(url.searchParams.get("maxAgeHours") ?? "168") || 168;
  const forceFullSync = url.searchParams.get("forceFullSync") === "true";
  const includeEnrichment =
    url.searchParams.get("includeEnrichment") === "true";

  // ── Credentials ──
  const username = process.env.ETERRA_USERNAME;
  const password = process.env.ETERRA_PASSWORD;
  if (!username || !password) {
    return NextResponse.json(
      { error: "ETERRA_USERNAME / ETERRA_PASSWORD not configured" },
      { status: 500 },
    );
  }

  // ── Health check ──
  const health = await checkEterraHealthNow();
  if (!health.available) {
    return NextResponse.json({
      processed: 0,
      skipped: 0,
      errors: 0,
      duration: "0s",
      message: `eTerra indisponibil: ${health.message ?? "maintenance"}`,
      details: [],
    });
  }

  // ── Find UATs with data in DB ──
  const uatGroups = await prisma.gisFeature.groupBy({
    by: ["siruta"],
    _count: { id: true },
  });

  // Resolve UAT names
  const sirutas = uatGroups.map((g) => g.siruta);
  const uatRecords = await prisma.gisUat.findMany({
    where: { siruta: { in: sirutas } },
    select: { siruta: true, name: true },
  });
  const nameMap = new Map(uatRecords.map((u) => [u.siruta, u.name]));

  // ── Check freshness per UAT ──
  type UatCandidate = {
    siruta: string;
    uatName: string;
    featureCount: number;
    terenuriStale: boolean;
    cladiriStale: boolean;
    enrichedCount: number;
    totalCount: number;
  };

  const stale: UatCandidate[] = [];
  const fresh: string[] = [];

  for (const group of uatGroups) {
    const sir = group.siruta;
    const [tStatus, cStatus] = await Promise.all([
      getLayerFreshness(sir, "TERENURI_ACTIVE"),
      getLayerFreshness(sir, "CLADIRI_ACTIVE"),
    ]);
    const tFresh = isFresh(tStatus.lastSynced, maxAgeHours);
    const cFresh = isFresh(cStatus.lastSynced, maxAgeHours);

    if (forceFullSync || !tFresh || !cFresh) {
      stale.push({
        siruta: sir,
        uatName: nameMap.get(sir) ?? sir,
        featureCount: group._count.id,
        terenuriStale: !tFresh || forceFullSync,
        cladiriStale: !cFresh || forceFullSync,
        enrichedCount: tStatus.enrichedCount,
        totalCount: tStatus.featureCount + cStatus.featureCount,
      });
    } else {
      fresh.push(sir);
    }
  }

  // Shuffle stale UATs so we don't always process the same ones first
  for (let i = stale.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [stale[i]!, stale[j]!] = [stale[j]!, stale[i]!];
  }

  const toProcess = stale.slice(0, maxUats);
  const startTime = Date.now();
  const details: UatRefreshResult[] = [];
  let errorCount = 0;

  // ── Process stale UATs ──
  for (let idx = 0; idx < toProcess.length; idx++) {
    const uat = toProcess[idx]!;

    // Random delay between UATs (30-120s) to spread load
    if (idx > 0) {
      const delay = 30_000 + Math.random() * 90_000;
      await sleep(delay);
    }

    const uatStart = Date.now();
    console.log(
      `[auto-refresh] Processing UAT ${uat.siruta} (${uat.uatName})...`,
    );

    try {
      let terenuriResult = { newFeatures: 0, removedFeatures: 0 };
      let cladiriResult = { newFeatures: 0, removedFeatures: 0 };

      if (uat.terenuriStale) {
        const res = await syncLayer(username, password, uat.siruta, "TERENURI_ACTIVE", {
          uatName: uat.uatName,
          forceFullSync,
        });
        terenuriResult = { newFeatures: res.newFeatures, removedFeatures: res.removedFeatures };
      }

      if (uat.cladiriStale) {
        const res = await syncLayer(username, password, uat.siruta, "CLADIRI_ACTIVE", {
          uatName: uat.uatName,
          forceFullSync,
        });
        cladiriResult = { newFeatures: res.newFeatures, removedFeatures: res.removedFeatures };
      }

      // Optional: re-enrich if partial enrichment
      if (includeEnrichment && uat.enrichedCount < uat.totalCount) {
        try {
          const { EterraClient } = await import(
            "@/modules/parcel-sync/services/eterra-client"
          );
          const { enrichFeatures } = await import(
            "@/modules/parcel-sync/services/enrich-service"
          );
          const enrichClient = await EterraClient.create(username, password);
          await enrichFeatures(enrichClient, uat.siruta);
        } catch (enrichErr) {
          console.warn(
            `[auto-refresh] Enrichment failed for ${uat.siruta}:`,
            enrichErr instanceof Error ? enrichErr.message : enrichErr,
          );
        }
      }

      const durationMs = Date.now() - uatStart;
      console.log(
        `[auto-refresh] UAT ${uat.siruta}: terenuri +${terenuriResult.newFeatures}/-${terenuriResult.removedFeatures}, cladiri +${cladiriResult.newFeatures}/-${cladiriResult.removedFeatures} (${(durationMs / 1000).toFixed(1)}s)`,
      );

      details.push({
        siruta: uat.siruta,
        uatName: uat.uatName,
        action: "synced",
        terenuri: { new: terenuriResult.newFeatures, removed: terenuriResult.removedFeatures },
        cladiri: { new: cladiriResult.newFeatures, removed: cladiriResult.removedFeatures },
        durationMs,
      });
    } catch (error) {
      errorCount++;
      const msg = error instanceof Error ? error.message : "Unknown error";
      console.error(`[auto-refresh] Error on UAT ${uat.siruta}: ${msg}`);
      details.push({
        siruta: uat.siruta,
        uatName: uat.uatName,
        action: "error",
        reason: msg,
        durationMs: Date.now() - uatStart,
      });
    }
  }

  const totalDuration = Date.now() - startTime;
  const durationStr =
    totalDuration > 60_000
      ? `${Math.floor(totalDuration / 60_000)}m ${Math.round((totalDuration % 60_000) / 1000)}s`
      : `${Math.round(totalDuration / 1000)}s`;

  console.log(
    `[auto-refresh] Completed ${toProcess.length}/${stale.length} UATs, ${errorCount} errors (${durationStr})`,
  );

  return NextResponse.json({
    processed: toProcess.length,
    skipped: fresh.length,
    staleTotal: stale.length,
    errors: errorCount,
    duration: durationStr,
    details,
  });
}
