/**
 * POST /api/eterra/sync-county
 *
 * Starts a background sync for all UATs in a given county.
 * Syncs TERENURI_ACTIVE, CLADIRI_ACTIVE, and LIMITE_INTRAV_DYNAMIC.
 * UATs with >30% enrichment → magic mode (sync + enrichment).
 *
 * Body: { county: string }
 * Returns immediately with jobId — progress via /api/eterra/progress.
 */

import { prisma } from "@/core/storage/prisma";
import {
  setProgress,
  clearProgress,
  type SyncProgress,
} from "@/modules/parcel-sync/services/progress-store";
import { syncLayer } from "@/modules/parcel-sync/services/sync-service";
import { enrichFeatures } from "@/modules/parcel-sync/services/enrich-service";
import { EterraClient } from "@/modules/parcel-sync/services/eterra-client";
import { checkEterraHealthNow } from "@/modules/parcel-sync/services/eterra-health";
import { createAppNotification } from "@/core/notifications/app-notifications";
import { getSessionCredentials } from "@/modules/parcel-sync/services/session-store";
import { firePmtilesRebuild } from "@/modules/parcel-sync/services/pmtiles-webhook";

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

/* Concurrency guard */
const g = globalThis as { __countySyncRunning?: string; __allCountiesSyncRunning?: boolean };

export async function POST(req: Request) {
  let body: { county?: string };
  try {
    body = (await req.json()) as { county?: string };
  } catch {
    return Response.json({ error: "Body invalid" }, { status: 400 });
  }

  const session = getSessionCredentials();
  const username = String(session?.username || process.env.ETERRA_USERNAME || "").trim();
  const password = String(session?.password || process.env.ETERRA_PASSWORD || "").trim();
  if (!username || !password) {
    return Response.json(
      { error: "Credentiale lipsa — conecteaza-te la eTerra mai intai." },
      { status: 401 },
    );
  }

  const county = body.county?.trim();
  if (!county) {
    return Response.json({ error: "Judetul lipseste" }, { status: 400 });
  }

  if (g.__allCountiesSyncRunning) {
    return Response.json(
      { error: "Sync All Romania in curs — asteapta sa se termine" },
      { status: 409 },
    );
  }

  if (g.__countySyncRunning) {
    return Response.json(
      { error: `Sync judet deja in curs: ${g.__countySyncRunning}` },
      { status: 409 },
    );
  }

  const jobId = crypto.randomUUID();
  g.__countySyncRunning = county;

  setProgress({
    jobId,
    downloaded: 0,
    total: 100,
    status: "running",
    phase: `Pregatire sync ${county}`,
  });

  void runCountySync(jobId, county, username, password);

  return Response.json(
    { jobId, message: `Sync judet ${county} pornit` },
    { status: 202 },
  );
}

async function runCountySync(
  jobId: string,
  county: string,
  username: string,
  password: string,
) {
  const push = (p: Partial<SyncProgress>) =>
    setProgress({
      jobId,
      downloaded: 0,
      total: 100,
      status: "running",
      ...p,
    } as SyncProgress);

  try {
    // Health check
    const health = await checkEterraHealthNow();
    if (!health.available) {
      setProgress({
        jobId,
        downloaded: 0,
        total: 100,
        status: "error",
        phase: "eTerra indisponibil",
        message: health.message ?? "maintenance",
      });
      await createAppNotification({
        type: "sync-error",
        title: `Sync ${county}: eTerra indisponibil`,
        message: health.message ?? "Serviciul eTerra este in mentenanta",
        metadata: { county, jobId },
      });
      g.__countySyncRunning = undefined;
      setTimeout(() => clearProgress(jobId), 3_600_000);
      return;
    }

    // Find all UATs in this county with feature stats
    const uats = await prisma.$queryRawUnsafe<
      Array<{
        siruta: string;
        name: string | null;
        total: number;
        enriched: number;
      }>
    >(
      `SELECT u.siruta, u.name,
         COALESCE(f.total, 0)::int as total,
         COALESCE(f.enriched, 0)::int as enriched
       FROM "GisUat" u
       LEFT JOIN (
         SELECT siruta, COUNT(*)::int as total,
           COUNT(*) FILTER (WHERE "enrichedAt" IS NOT NULL)::int as enriched
         FROM "GisFeature"
         WHERE "layerId" IN ('TERENURI_ACTIVE','CLADIRI_ACTIVE') AND "objectId" > 0
         GROUP BY siruta
       ) f ON u.siruta = f.siruta
       WHERE u.county = $1
       ORDER BY COALESCE(f.total, 0) DESC`,
      county,
    );

    if (uats.length === 0) {
      setProgress({
        jobId,
        downloaded: 100,
        total: 100,
        status: "done",
        phase: `Niciun UAT gasit in ${county}`,
      });
      g.__countySyncRunning = undefined;
      setTimeout(() => clearProgress(jobId), 3_600_000);
      return;
    }

    const results: Array<{
      siruta: string;
      name: string;
      mode: string;
      duration: number;
      note: string;
    }> = [];
    let errors = 0;

    let totalNewFeatures = 0;

    for (let i = 0; i < uats.length; i++) {
      const uat = uats[i]!;
      const uatName = uat.name ?? uat.siruta;
      const ratio = uat.total > 0 ? uat.enriched / uat.total : 0;
      const isMagic = ratio > 0.3;
      const mode = isMagic ? "magic" : "base";
      const pct = Math.round((i / uats.length) * 100);

      push({
        downloaded: pct,
        total: 100,
        phase: `[${i + 1}/${uats.length}] ${uatName} (${mode})`,
        note:
          results.length > 0
            ? `Ultimul: ${results[results.length - 1]!.name} — ${results[results.length - 1]!.note}`
            : undefined,
      });

      const uatStart = Date.now();
      try {
        // Sync TERENURI + CLADIRI — pass jobId for sub-progress
        const tRes = await syncLayer(username, password, uat.siruta, "TERENURI_ACTIVE", {
          uatName, jobId, isSubStep: true,
        });
        const cRes = await syncLayer(username, password, uat.siruta, "CLADIRI_ACTIVE", {
          uatName, jobId, isSubStep: true,
        });

        // Sync ADMINISTRATIV (intravilan) — wrapped in try/catch since it needs UAT geometry
        let adminNote = "";
        try {
          const aRes = await syncLayer(
            username,
            password,
            uat.siruta,
            "LIMITE_INTRAV_DYNAMIC",
            { uatName, jobId, isSubStep: true },
          );
          if (aRes.newFeatures > 0) {
            adminNote = ` | A:+${aRes.newFeatures}`;
          }
        } catch {
          adminNote = " | A:skip";
        }

        // Enrichment for magic mode
        let enrichNote = "";
        if (isMagic) {
          const client = await EterraClient.create(username, password, {
            timeoutMs: 120_000,
          });
          const eRes = await enrichFeatures(client, uat.siruta);
          enrichNote =
            eRes.status === "done"
              ? ` | enrich: ${eRes.enrichedCount}/${eRes.totalFeatures ?? "?"}`
              : ` | enrich err: ${eRes.error}`;
        }

        const dur = Math.round((Date.now() - uatStart) / 1000);
        const parts = [
          tRes.newFeatures > 0 || (tRes.validFromUpdated ?? 0) > 0
            ? `T:+${tRes.newFeatures}/${tRes.validFromUpdated ?? 0}vf`
            : "T:ok",
          cRes.newFeatures > 0 || (cRes.validFromUpdated ?? 0) > 0
            ? `C:+${cRes.newFeatures}/${cRes.validFromUpdated ?? 0}vf`
            : "C:ok",
        ];
        totalNewFeatures += tRes.newFeatures + cRes.newFeatures;
        const note = `${parts.join(", ")}${adminNote}${enrichNote} (${dur}s)`;
        results.push({ siruta: uat.siruta, name: uatName, mode, duration: dur, note });

        // Update progress AFTER UAT completion (so % reflects completed work)
        const completedPct = Math.round(((i + 1) / uats.length) * 100);
        push({
          downloaded: completedPct,
          total: 100,
          phase: `[${i + 1}/${uats.length}] ${uatName} finalizat`,
          note: `${note}`,
        });

        console.log(`[sync-county:${county}] ${i + 1}/${uats.length} ${uatName}: ${note}`);
      } catch (err) {
        errors++;
        const dur = Math.round((Date.now() - uatStart) / 1000);
        const msg = err instanceof Error ? err.message : "Unknown";
        results.push({
          siruta: uat.siruta,
          name: uatName,
          mode,
          duration: dur,
          note: `ERR: ${msg}`,
        });
        // Still update progress after error
        const completedPct = Math.round(((i + 1) / uats.length) * 100);
        push({
          downloaded: completedPct,
          total: 100,
          phase: `[${i + 1}/${uats.length}] ${uatName} — eroare`,
        });
        console.error(`[sync-county:${county}] ${uatName}: ${msg}`);
      }
    }

    const totalDur = results.reduce((s, r) => s + r.duration, 0);
    const summary = `${uats.length} UAT-uri, ${errors} erori, ${totalDur}s total`;

    setProgress({
      jobId,
      downloaded: 100,
      total: 100,
      status: errors > 0 && errors === uats.length ? "error" : "done",
      phase: `Sync ${county} finalizat`,
      message: summary,
      note: results.map((r) => `${r.name}: ${r.note}`).join("\n"),
    });

    await createAppNotification({
      type: errors > 0 ? "sync-error" : "sync-complete",
      title:
        errors > 0
          ? `Sync ${county}: ${errors} erori din ${uats.length} UAT-uri`
          : `Sync ${county}: ${uats.length} UAT-uri sincronizate`,
      message: summary,
      metadata: { county, jobId, uatCount: uats.length, errors, totalDuration: totalDur },
    });

    console.log(`[sync-county:${county}] Done: ${summary}`);

    // Trigger PMTiles rebuild if new features were synced
    if (totalNewFeatures > 0) {
      await firePmtilesRebuild("county-sync-complete", {
        county,
        uatCount: uats.length,
        newFeatures: totalNewFeatures,
        errors,
      });
    }

    setTimeout(() => clearProgress(jobId), 6 * 3_600_000);
  } catch (err) {
    const msg = err instanceof Error ? err.message : "Unknown";
    setProgress({
      jobId,
      downloaded: 0,
      total: 100,
      status: "error",
      phase: "Eroare",
      message: msg,
    });
    await createAppNotification({
      type: "sync-error",
      title: `Sync ${county}: eroare generala`,
      message: msg,
      metadata: { county, jobId },
    });
    setTimeout(() => clearProgress(jobId), 3_600_000);
  } finally {
    g.__countySyncRunning = undefined;
  }
}
