import { NextResponse } from "next/server";
import { PrismaClient, Prisma } from "@prisma/client";
import {
  isWeekendWindow,
  getWeekendSyncActivity,
  triggerForceSync,
} from "@/modules/parcel-sync/services/weekend-deep-sync";

const prisma = new PrismaClient();

const g = globalThis as { __parcelSyncRunning?: boolean };

const KV_NAMESPACE = "parcel-sync-weekend";
const KV_KEY = "queue-state";

type StepName = "sync_terenuri" | "sync_cladiri" | "import_nogeom" | "enrich";
type StepStatus = "pending" | "done" | "error";

type CityState = {
  siruta: string;
  name: string;
  county: string;
  priority: number;
  steps: Record<StepName, StepStatus>;
  lastActivity?: string;
  errorMessage?: string;
};

type WeekendSyncState = {
  cities: CityState[];
  lastSessionDate?: string;
  totalSessions: number;
  completedCycles: number;
};

const FRESH_STEPS: Record<StepName, StepStatus> = {
  sync_terenuri: "pending",
  sync_cladiri: "pending",
  import_nogeom: "pending",
  enrich: "pending",
};

const DEFAULT_CITIES: Omit<CityState, "steps">[] = [
  { siruta: "54975", name: "Cluj-Napoca", county: "Cluj", priority: 1 },
  { siruta: "32394", name: "Bistri\u021Ba", county: "Bistri\u021Ba-N\u0103s\u0103ud", priority: 1 },
  { siruta: "114319", name: "T\u00E2rgu Mure\u0219", county: "Mure\u0219", priority: 2 },
  { siruta: "139704", name: "Zal\u0103u", county: "S\u0103laj", priority: 2 },
  { siruta: "26564", name: "Oradea", county: "Bihor", priority: 2 },
  { siruta: "9262", name: "Arad", county: "Arad", priority: 2 },
  { siruta: "155243", name: "Timi\u0219oara", county: "Timi\u0219", priority: 2 },
  { siruta: "143450", name: "Sibiu", county: "Sibiu", priority: 2 },
  { siruta: "40198", name: "Bra\u0219ov", county: "Bra\u0219ov", priority: 2 },
];

/** Initialize state with default cities if not present in DB */
async function getOrCreateState(): Promise<WeekendSyncState> {
  const row = await prisma.keyValueStore.findUnique({
    where: { namespace_key: { namespace: KV_NAMESPACE, key: KV_KEY } },
  });
  if (row?.value && typeof row.value === "object") {
    return row.value as unknown as WeekendSyncState;
  }
  // First access — initialize with defaults
  const state: WeekendSyncState = {
    cities: DEFAULT_CITIES.map((c) => ({ ...c, steps: { ...FRESH_STEPS } })),
    totalSessions: 0,
    completedCycles: 0,
  };
  await prisma.keyValueStore.upsert({
    where: { namespace_key: { namespace: KV_NAMESPACE, key: KV_KEY } },
    update: { value: state as unknown as Prisma.InputJsonValue },
    create: {
      namespace: KV_NAMESPACE,
      key: KV_KEY,
      value: state as unknown as Prisma.InputJsonValue,
    },
  });
  return state;
}

/**
 * GET /api/eterra/weekend-sync
 * Returns the current queue state.
 */
export async function GET() {
  // Auth handled by middleware (route is not excluded)
  const state = await getOrCreateState();
  const sirutas = state.cities.map((c) => c.siruta);

  const counts = await prisma.gisFeature.groupBy({
    by: ["siruta", "layerId"],
    where: { siruta: { in: sirutas } },
    _count: { id: true },
  });

  const enrichedCounts = await prisma.gisFeature.groupBy({
    by: ["siruta"],
    where: { siruta: { in: sirutas }, enrichedAt: { not: null } },
    _count: { id: true },
  });

  const enrichedMap = new Map(enrichedCounts.map((e) => [e.siruta, e._count.id]));

  type CityStats = {
    terenuri: number;
    cladiri: number;
    total: number;
    enriched: number;
  };
  const statsMap = new Map<string, CityStats>();

  for (const c of counts) {
    const existing = statsMap.get(c.siruta) ?? { terenuri: 0, cladiri: 0, total: 0, enriched: 0 };
    existing.total += c._count.id;
    if (c.layerId === "TERENURI_ACTIVE") existing.terenuri = c._count.id;
    if (c.layerId === "CLADIRI_ACTIVE") existing.cladiri = c._count.id;
    existing.enriched = enrichedMap.get(c.siruta) ?? 0;
    statsMap.set(c.siruta, existing);
  }

  const citiesWithStats = state.cities.map((c) => ({
    ...c,
    dbStats: statsMap.get(c.siruta) ?? { terenuri: 0, cladiri: 0, total: 0, enriched: 0 },
  }));

  // Determine live sync status
  const running = !!g.__parcelSyncRunning;
  const activity = getWeekendSyncActivity();
  const inWindow = isWeekendWindow();
  const hasErrors = state.cities.some((c) =>
    (Object.values(c.steps) as StepStatus[]).some((s) => s === "error"),
  );

  type SyncStatus = "running" | "error" | "waiting" | "idle";
  let syncStatus: SyncStatus = "idle";
  if (running) syncStatus = "running";
  else if (hasErrors) syncStatus = "error";
  else if (inWindow) syncStatus = "waiting";

  return NextResponse.json({
    state: { ...state, cities: citiesWithStats },
    syncStatus,
    currentActivity: activity,
    inWeekendWindow: inWindow,
  });
}

/**
 * POST /api/eterra/weekend-sync
 * Modify the queue: add/remove cities, reset steps, change priority.
 */
export async function POST(request: Request) {
  // Auth handled by middleware (route is not excluded)
  const body = (await request.json()) as {
    action: "add" | "remove" | "reset" | "reset_all" | "set_priority" | "trigger";
    siruta?: string;
    name?: string;
    county?: string;
    priority?: number;
    onlySteps?: string[];
  };

  // Trigger is handled separately — starts sync immediately
  if (body.action === "trigger") {
    const validSteps = ["sync_terenuri", "sync_cladiri", "import_nogeom", "enrich"] as const;
    const onlySteps = body.onlySteps?.filter((s): s is (typeof validSteps)[number] =>
      (validSteps as readonly string[]).includes(s),
    );
    const result = await triggerForceSync(
      onlySteps && onlySteps.length > 0 ? { onlySteps } : undefined,
    );
    if (!result.started) {
      return NextResponse.json(
        { error: result.reason },
        { status: 409 },
      );
    }
    return NextResponse.json({ ok: true, message: "Sincronizare pornita" });
  }

  const state = await getOrCreateState();

  switch (body.action) {
    case "add": {
      if (!body.siruta || !body.name) {
        return NextResponse.json(
          { error: "siruta si name sunt obligatorii" },
          { status: 400 },
        );
      }
      if (state.cities.some((c) => c.siruta === body.siruta)) {
        return NextResponse.json(
          { error: `${body.name} (${body.siruta}) e deja in coada` },
          { status: 409 },
        );
      }
      state.cities.push({
        siruta: body.siruta,
        name: body.name,
        county: body.county ?? "",
        priority: body.priority ?? 3,
        steps: { ...FRESH_STEPS },
      });
      break;
    }
    case "remove": {
      state.cities = state.cities.filter((c) => c.siruta !== body.siruta);
      break;
    }
    case "reset": {
      const city = state.cities.find((c) => c.siruta === body.siruta);
      if (city) {
        city.steps = { ...FRESH_STEPS };
        city.errorMessage = undefined;
      }
      break;
    }
    case "reset_all": {
      for (const city of state.cities) {
        city.steps = { ...FRESH_STEPS };
        city.errorMessage = undefined;
      }
      state.completedCycles = 0;
      break;
    }
    case "set_priority": {
      const city = state.cities.find((c) => c.siruta === body.siruta);
      if (city && body.priority != null) {
        city.priority = body.priority;
      }
      break;
    }
  }

  await prisma.keyValueStore.upsert({
    where: { namespace_key: { namespace: KV_NAMESPACE, key: KV_KEY } },
    update: { value: state as unknown as Prisma.InputJsonValue },
    create: {
      namespace: KV_NAMESPACE,
      key: KV_KEY,
      value: state as unknown as Prisma.InputJsonValue,
    },
  });

  return NextResponse.json({ ok: true, cities: state.cities.length });
}
