"use client";

import { useEffect, useRef, useState } from "react";
import dynamic from "next/dynamic";
import { LatLng, Zone, ZoneType } from "@/lib/api";
import { loadGoogleMaps } from "@/lib/googleMaps";
import { useMapsConfig } from "@/lib/useMapsConfig";
import { useLocale } from "@/i18n/LocaleProvider";

// mapbox-gl is ~250 kB; only pull it in when the Mapbox branch actually renders (client-only).
const MapboxZoneMap = dynamic(
  () => import("@/components/MapboxZoneMap").then((m) => m.MapboxZoneMap),
  {
    ssr: false,
    // Sized by the parent so the placeholder occupies exactly the space the map will.
    loading: () => <div className="h-full w-full animate-pulse rounded-card bg-surface-raised" />,
  },
);

/**
 * The bundled @types/google.maps ships an empty DrawingManager (no setMap/setDrawingMode). Rather
 * than pin an older type package, declare the two methods we actually call. The runtime object has
 * them, this only fills a gap in the published types.
 */
type DrawingManagerLike = google.maps.drawing.DrawingManager & {
  setMap(map: google.maps.Map | null): void;
  setDrawingMode(mode: google.maps.drawing.OverlayType | null): void;
};

/** Zone type → fill/stroke. Matches the design-system semantic tones. */
const ZONE_COLORS: Record<ZoneType, string> = {
  GREEN: "#22C55E",
  RED: "#EF4444",
  SLOW: "#F59E0B",
  COMPOUND: "#A855F7",
  // Blue, deliberately not green: a parking spot sits inside the green operating area, and two
  // greens on one map make it impossible to see which is which.
  PARKING: "#3B82F6",
};

const RIYADH = { lat: 24.7136, lng: 46.6753 };

/**
 * The zones map: renders every zone as a coloured polygon and lets the operator draw a new one.
 *
 * A finished drawing is handed up via `onDrawn` as plain lat/lng points, the map knows nothing
 * about zone types or the API, so this component swaps cleanly if the provider ever changes.
 */
export function ZoneMap({
  zones,
  selectedId,
  drawing,
  onDrawn,
  onSelect,
  className = "h-[520px] w-full overflow-hidden rounded-card border border-line",
}: {
  zones: Zone[];
  selectedId: string | null;
  drawing: boolean;
  onDrawn: (polygon: LatLng[]) => void;
  onSelect: (id: string) => void;
  className?: string;
}) {
  const { t } = useLocale();
  const ref = useRef<HTMLDivElement>(null);
  const mapRef = useRef<google.maps.Map | null>(null);
  const drawnRef = useRef<google.maps.Polygon[]>([]);
  const managerRef = useRef<DrawingManagerLike | null>(null);
  const [error, setError] = useState(false);

  // Key + provider come from the vault at runtime (API Keys page), not a build-time env var.
  const { config, loading } = useMapsConfig();
  const provider = config?.provider ?? null;
  const key = config?.apiKey ?? null;
  // Provider-aware: Mapbox and Google are both supported; the vault's maps.provider chooses.
  const googleReady = !!key && (provider === "google" || provider === null);
  const mapboxReady = !!key && provider === "mapbox";

  // --- one-time map init ---------------------------------------------------
  useEffect(() => {
    if (!googleReady || !key || !ref.current) return;
    let cancelled = false;

    loadGoogleMaps(key)
      .then((maps) => {
        if (cancelled || !ref.current) return;
        mapRef.current = new maps.Map(ref.current, {
          center: RIYADH,
          zoom: 12,
          disableDefaultUI: true,
          zoomControl: true,
          // A dark style would come from a styled map id; NORMAL until that's authored.
          mapTypeId: maps.MapTypeId.ROADMAP,
        });
      })
      .catch(() => setError(true));

    return () => {
      cancelled = true;
    };
  }, [key]);

  // --- render existing zones as polygons -----------------------------------
  useEffect(() => {
    const map = mapRef.current;
    if (!map || !window.google) return;

    drawnRef.current.forEach((p) => p.setMap(null));
    drawnRef.current = [];

    zones.forEach((zone) => {
      const color = ZONE_COLORS[zone.type];
      const selected = zone.id === selectedId;
      const polygon = new google.maps.Polygon({
        paths: zone.polygon,
        strokeColor: color,
        strokeOpacity: zone.active ? 0.9 : 0.35,
        strokeWeight: selected ? 4 : 2,
        fillColor: color,
        fillOpacity: zone.active ? (selected ? 0.35 : 0.18) : 0.06,
        map,
        clickable: true,
      });
      polygon.addListener("click", () => onSelect(zone.id));
      drawnRef.current.push(polygon);
    });
  }, [zones, selectedId, onSelect]);

  // --- drawing mode --------------------------------------------------------
  useEffect(() => {
    const map = mapRef.current;
    if (!map || !window.google?.maps?.drawing) return;

    if (!drawing) {
      managerRef.current?.setMap(null);
      managerRef.current = null;
      return;
    }

    // Constructor options are also missing from this @types version, cast the ctor.
    const Manager = google.maps.drawing.DrawingManager as unknown as new (
      opts: Record<string, unknown>,
    ) => DrawingManagerLike;
    const manager = new Manager({
      drawingMode: google.maps.drawing.OverlayType.POLYGON,
      drawingControl: false,
      polygonOptions: {
        strokeColor: "#FCD704",
        fillColor: "#FCD704",
        fillOpacity: 0.2,
        strokeWeight: 2,
      },
    });
    manager.setMap(map);
    managerRef.current = manager;

    const listener = google.maps.event.addListener(
      manager,
      "polygoncomplete",
      (poly: google.maps.Polygon) => {
        const points: LatLng[] = poly
          .getPath()
          .getArray()
          .map((p) => ({ lat: p.lat(), lng: p.lng() }));
        // Remove the drawing overlay, the parent re-renders it as a saved zone.
        poly.setMap(null);
        manager.setDrawingMode(null);
        onDrawn(points);
      },
    );

    return () => google.maps.event.removeListener(listener);
  }, [drawing, onDrawn]);

  if (loading) {
    return <div className={`${className} animate-pulse bg-surface-raised`} />;
  }
  if (mapboxReady && key) {
    return (
      <MapboxZoneMap
        token={key}
        zones={zones}
        selectedId={selectedId}
        drawing={drawing}
        onDrawn={onDrawn}
        onSelect={onSelect}
        className={className}
      />
    );
  }
  if (!key) {
    return (
      <div className={`${className} flex items-center justify-center p-6 text-center`}>
        <p className="max-w-sm text-sm text-muted">{t("zones.noMapKey")}</p>
      </div>
    );
  }
  if (!googleReady) {
    // A key is set but for a provider this component can't render yet.
    return (
      <div className={`${className} flex items-center justify-center p-6 text-center`}>
        <p className="max-w-sm text-sm text-muted">{t("zones.providerUnsupported")}</p>
      </div>
    );
  }
  if (error) {
    return (
      <div className={`${className} flex items-center justify-center p-6 text-center`}>
        <p className="text-sm text-danger">{t("zones.mapError")}</p>
      </div>
    );
  }

  return (
    <div
      ref={ref}
      className={className}
    />
  );
}

export { ZONE_COLORS };
