import type {
  DashboardKpis,
  EveningCheckResult,
  FleetSnapshot,
  ReadinessResult,
  SimulateEventPayload,
  SiteId,
  VehicleGroup,
  VehicleMaster,
} from "@/lib/fleet/types";
import { evaluateEveningCheck } from "@/lib/fleet/evening";
import { evaluateReadiness } from "@/lib/fleet/readiness";
import { isStale, newestTelematicsTimestamp } from "@/lib/fleet/geo";
import { EVENING_THRESHOLDS } from "@/lib/fleet/evening";
import { READINESS_THRESHOLDS } from "@/lib/fleet/readiness";
import { isInExpectedZone } from "@/lib/fleet/geo";

async function getJson<T>(path: string): Promise<T> {
  const res = await fetch(path, { cache: "no-store" });
  if (!res.ok) {
    const body = await res.text();
    throw new Error(body || `HTTP ${res.status}`);
  }
  return res.json() as Promise<T>;
}

export async function fetchFleet(): Promise<FleetSnapshot> {
  return getJson<FleetSnapshot>("/api/fleet");
}

export async function fetchVehicle(vin: string): Promise<VehicleMaster> {
  return getJson<VehicleMaster>(`/api/fleet/vehicles/${encodeURIComponent(vin)}`);
}

export async function simulateFleetEvent(
  payload: SimulateEventPayload = {},
): Promise<VehicleMaster> {
  const res = await fetch("/api/fleet/simulate", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload),
  });
  if (!res.ok) throw new Error(await res.text());
  return res.json() as Promise<VehicleMaster>;
}

export async function resetFleet(): Promise<FleetSnapshot> {
  const res = await fetch("/api/fleet/reset", { method: "POST" });
  if (!res.ok) throw new Error(await res.text());
  return res.json() as Promise<FleetSnapshot>;
}

export function filterVehicles(
  vehicles: VehicleMaster[],
  opts: {
    siteId?: SiteId | "all";
    group?: VehicleGroup | "all";
    query?: string;
  },
): VehicleMaster[] {
  const q = opts.query?.trim().toLowerCase() ?? "";
  return vehicles.filter((v) => {
    if (opts.siteId && opts.siteId !== "all" && v.expectedSiteId !== opts.siteId) {
      return false;
    }
    if (opts.group && opts.group !== "all" && v.group !== opts.group) {
      return false;
    }
    if (!q) return true;
    return (
      v.vin.toLowerCase().includes(q) ||
      v.licensePlate.toLowerCase().includes(q) ||
      v.model.toLowerCase().includes(q) ||
      v.color.toLowerCase().includes(q)
    );
  });
}

export function computeKpis(
  snapshot: FleetSnapshot,
  siteId: SiteId | "all" = "all",
): DashboardKpis {
  const vehicles = filterVehicles(snapshot.vehicles, { siteId });
  let readyForHandover = 0;
  let chargingIssues = 0;
  let healthAlerts = 0;
  let zoneMismatches = 0;
  let staleData = 0;

  for (const v of vehicles) {
    const readiness = evaluateReadiness(v, snapshot.sites);
    if (readiness.ready) readyForHandover += 1;
    if (
      readiness.issues.some((i) => i.code === "HEALTH_WARNING") ||
      evaluateEveningCheck(v, snapshot.sites).issues.some(
        (i) => i.code === "CRITICAL_HEALTH",
      )
    ) {
      healthAlerts += 1;
    }
    if (
      v.battery &&
      (v.battery.chargingStatus === "ERROR" ||
        v.battery.chargerConnectionStatus === "FAULT" ||
        (v.battery.chargerConnectionStatus === "CONNECTED" &&
          v.battery.chargingStatus === "IDLE" &&
          v.battery.batteryChargeLevelPercentage <
            READINESS_THRESHOLDS.minBatteryPct))
    ) {
      chargingIssues += 1;
    }
    const stamp = newestTelematicsTimestamp(v);
    if (isStale(stamp, EVENING_THRESHOLDS.staleMinutes)) staleData += 1;
    else if (!isInExpectedZone(v, snapshot.sites)) zoneMismatches += 1;
  }

  return {
    totalVehicles: vehicles.length,
    readyForHandover,
    chargingIssues,
    healthAlerts,
    zoneMismatches,
    staleData,
  };
}

export function withReadiness(
  snapshot: FleetSnapshot,
  vehicles: VehicleMaster[],
): { vehicle: VehicleMaster; readiness: ReadinessResult }[] {
  return vehicles.map((vehicle) => ({
    vehicle,
    readiness: evaluateReadiness(vehicle, snapshot.sites),
  }));
}

export function withEvening(
  snapshot: FleetSnapshot,
  vehicles: VehicleMaster[],
): { vehicle: VehicleMaster; evening: EveningCheckResult }[] {
  return vehicles.map((vehicle) => ({
    vehicle,
    evening: evaluateEveningCheck(vehicle, snapshot.sites),
  }));
}
