"use client";

import { useEffect, useMemo, useState } from "react";
import { Vehicle, VehicleType } from "@/lib/api";
import { useLocale } from "@/i18n/LocaleProvider";
import { useVehicleTypes } from "@/lib/useVehicleTypes";
import { FLEET_COLORS, FleetMap, FleetTone, fleetTone } from "@/components/FleetMap";
import { Button, Card, Field, Modal, Numeric, Select, StatusBadge } from "@/components/ui";

const TONES: FleetTone[] = ["available", "inUse", "lowBattery", "maintenance", "offline"];

/** How often the map refreshes while it is on screen. */
const POLL_MS = 10_000;

/**
 * The live fleet map: where every vehicle is, filtered down to the ones worth looking at.
 *
 * <p>The filters are the point. A map of a whole city's fleet is an undifferentiated field of
 * dots; what an operator actually asks is "show me the flat batteries in this district" or
 * "which ones have stopped reporting". So the counts double as the filter control, and clicking
 * a tone both narrows the map and says how many there are.
 */
export function FleetMapPanel({
  vehicles,
  selectedId,
  onSelect,
  onRefresh,
}: {
  vehicles: Vehicle[];
  selectedId: string | null;
  onSelect: (v: Vehicle) => void;
  onRefresh: () => void;
}) {
  const { t } = useLocale();
  const [query, setQuery] = useState("");
  const [tone, setTone] = useState<FleetTone | "">("");
  const [type, setType] = useState<VehicleType | "">("");
  const [maxBattery, setMaxBattery] = useState("");
  const [live, setLive] = useState(true);
  const vehicleTypes = useVehicleTypes();
  // Members of a cluster that zooming cannot separate. Empty when no picker is open.
  const [pickIds, setPickIds] = useState<string[]>([]);

  useEffect(() => {
    if (!live) return;
    const id = setInterval(onRefresh, POLL_MS);
    return () => clearInterval(id);
  }, [live, onRefresh]);

  // Counts are of the whole fleet, not the filtered set: a filter chip that recounted itself
  // after being applied could only ever show its own total, which tells the operator nothing.
  const counts = useMemo(() => {
    const acc = Object.fromEntries(TONES.map((x) => [x, 0])) as Record<FleetTone, number>;
    vehicles.forEach((v) => (acc[fleetTone(v)] += 1));
    return acc;
  }, [vehicles]);

  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase();
    const cap = maxBattery.trim() === "" ? null : Number(maxBattery);
    return vehicles.filter((v) => {
      if (tone && fleetTone(v) !== tone) return false;
      if (type && v.vehicleType !== type) return false;
      if (cap != null && Number.isFinite(cap) && v.batteryPercent > cap) return false;
      if (q && !`${v.qrCode} ${v.imei ?? ""} ${v.model ?? ""}`.toLowerCase().includes(q)) {
        return false;
      }
      return true;
    });
  }, [vehicles, query, tone, type, maxBattery]);

  // Worth saying out loud: a vehicle with no fix has never been anywhere we know about, so it
  // cannot be drawn. Silently dropping it would make the map disagree with the list.
  const unlocated = filtered.filter((v) => v.lastLat == null || v.lastLng == null).length;

  return (
    <div className="space-y-4">
      <Card>
        <div className="flex flex-wrap items-end gap-3">
          <Field
            label={t("fleetMap.search")}
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            placeholder="BEEB-0102"
            className="min-w-[200px] flex-1"
          />
          <Select
            label={t("fleetMap.type")}
            value={type}
            onChange={(e) => setType(e.target.value as VehicleType | "")}
            placeholder={t("fleetMap.allTypes")}
            options={vehicleTypes.options}
          />
          <Field
            label={t("fleetMap.batteryBelow")}
            value={maxBattery}
            onChange={(e) => setMaxBattery(e.target.value)}
            placeholder="20"
            inputMode="numeric"
            dir="ltr"
            className="w-32"
          />
          <Button onClick={() => setLive((v) => !v)}>
            {live ? t("fleetMap.liveOn") : t("fleetMap.liveOff")}
          </Button>
          <Button onClick={onRefresh}>{t("common.refresh")}</Button>
        </div>

        {/* Legend and filter in one control: the colours mean nothing until you can also use
            them to narrow what you are looking at. */}
        <div className="mt-4 flex flex-wrap gap-2">
          {TONES.map((x) => (
            <button
              key={x}
              type="button"
              onClick={() => setTone(tone === x ? "" : x)}
              aria-pressed={tone === x}
              className={`flex items-center gap-2 rounded-full border px-3 py-1.5 text-xs transition ${
                tone === x ? "border-brand bg-brand/15 text-foreground" : "border-line text-muted"
              }`}
            >
              <span
                className="h-2.5 w-2.5 rounded-full"
                style={{ backgroundColor: FLEET_COLORS[x] }}
              />
              {t(`fleetMap.tone.${x}` as never)}
              <Numeric>{counts[x]}</Numeric>
            </button>
          ))}
          {(tone || type || maxBattery || query) && (
            <Button
              variant="ghost"
              onClick={() => {
                setTone("");
                setType("");
                setMaxBattery("");
                setQuery("");
              }}
            >
              {t("fleetMap.clear")}
            </Button>
          )}
        </div>

        <p className="mt-3 text-xs text-muted">
          {t("fleetMap.showing")}: <Numeric>{filtered.length}</Numeric> / <Numeric>{vehicles.length}</Numeric>
          {unlocated > 0 && (
            <>
              {" · "}
              <span className="text-warning">
                <Numeric>{unlocated}</Numeric> {t("fleetMap.unlocated")}
              </span>
            </>
          )}
        </p>
      </Card>

      {/* Deliberately tall: this is the whole point of the tab, and a fleet map you have to
          scroll inside is a fleet map nobody uses. */}
      <FleetMap
        vehicles={filtered}
        selectedId={selectedId}
        onSelect={(id) => {
          const v = vehicles.find((x) => x.id === id);
          if (v) onSelect(v);
        }}
        onPickFrom={setPickIds}
        className="h-[calc(100vh-22rem)] min-h-[420px] w-full overflow-hidden rounded-card border border-line"
      />

      {/* Vehicles sharing one coordinate, e.g. a depot. The map cannot separate them however far
          you zoom, so they are listed instead of being unreachable under the top dot. */}
      <Modal
        open={pickIds.length > 0}
        onClose={() => setPickIds([])}
        title={t("fleetMap.pickTitle")}
        actions={<Button onClick={() => setPickIds([])}>{t("common.cancel")}</Button>}
      >
        <p className="mb-3 text-sm text-muted">{t("fleetMap.pickBody")}</p>
        <ul className="divide-y divide-line">
          {pickIds.map((id) => {
            const v = vehicles.find((x) => x.id === id);
            if (!v) return null;
            return (
              <li key={id}>
                <button
                  type="button"
                  onClick={() => {
                    setPickIds([]);
                    onSelect(v);
                  }}
                  className="flex w-full items-center gap-3 py-3 text-start transition hover:opacity-80"
                >
                  <span
                    className="h-2.5 w-2.5 shrink-0 rounded-full"
                    style={{ backgroundColor: FLEET_COLORS[fleetTone(v)] }}
                  />
                  <span className="flex-1 text-sm font-medium">
                    <Numeric>{v.qrCode}</Numeric>
                  </span>
                  <span className="text-xs text-muted">
                    <Numeric>{v.batteryPercent}%</Numeric>
                  </span>
                  <StatusBadge tone="neutral">
                    {t(`fleetMap.tone.${fleetTone(v)}` as never)}
                  </StatusBadge>
                </button>
              </li>
            );
          })}
        </ul>
      </Modal>

      <p className="text-xs text-muted">{t("fleetMap.hint")}</p>
    </div>
  );
}

/** The status chip used in the hover tooltip's list equivalent. */
export function FleetToneBadge({ vehicle }: { vehicle: Vehicle }) {
  const { t } = useLocale();
  const tone = fleetTone(vehicle);
  return <StatusBadge tone="neutral">{t(`fleetMap.tone.${tone}` as never)}</StatusBadge>;
}
