// map.jsx — shared Leaflet map with custom car pin, "me" dot, accuracy ring,
// optional draggable pin. Theme-aware tiles (CartoDB light/dark).

function carPinIcon(emoji) {
  const isVan = emoji === "🚐" || emoji === "🚌" || emoji === "🚚";
  const glyph = isVan
    ? '<path d="M3 7h11l4 4h2a1 1 0 0 1 1 1v4H3z M3 7v9" fill="none" stroke="#fff" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"/><circle cx="7.5" cy="16" r="1.6" fill="none" stroke="#fff" stroke-width="1.9"/><circle cx="16.5" cy="16" r="1.6" fill="none" stroke="#fff" stroke-width="1.9"/>'
    : '<path d="M3 13l1.8-4.6A2 2 0 0 1 6.7 7h10.6a2 2 0 0 1 1.9 1.4L21 13 M3 13h18v4a1 1 0 0 1-1 1h-1.5a1 1 0 0 1-1-1v-1H6.5v1a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1z" fill="none" stroke="#fff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>';
  return L.divIcon({
    className: "wmc-pin-wrap",
    html: `<div class="wmc-pin"><div class="wmc-pin-body"><svg width="20" height="20" viewBox="0 0 24 24" style="transform:rotate(45deg)">${glyph}</svg></div></div>`,
    iconSize: [36, 46],
    iconAnchor: [18, 44],
  });
}

function meIcon() {
  return L.divIcon({
    className: "wmc-me-wrap",
    html: `<div class="wmc-me"><div class="wmc-me-pulse"></div><div class="wmc-me-dot"></div></div>`,
    iconSize: [22, 22],
    iconAnchor: [11, 11],
  });
}

const TILES = {
  dark: "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
  light: "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
};
const TILE_ATTR = '&copy; OpenStreetMap &copy; CARTO';

function LeafletMap({
  carSpot, me, emoji = "🚗", center, zoom = 16, dark = true,
  draggable = false, onPinMove, interactive = true, fit = false, style = {},
}) {
  const elRef = React.useRef(null);
  const mapRef = React.useRef(null);
  const tileRef = React.useRef(null);
  const carRef = React.useRef(null);
  const meRef = React.useRef(null);
  const accRef = React.useRef(null);
  const [ready, setReady] = React.useState(false);

  // init once (poll until Leaflet is present)
  React.useEffect(() => {
    let raf;
    const tryInit = () => {
      if (!window.L || !elRef.current) { raf = requestAnimationFrame(tryInit); return; }
      const c = center || carSpot || me || { lat: 51.5114, lng: -0.1198 };
      const map = L.map(elRef.current, {
        center: [c.lat, c.lng], zoom, zoomControl: false, attributionControl: true,
        dragging: interactive, scrollWheelZoom: interactive, doubleClickZoom: interactive,
        boxZoom: interactive, keyboard: interactive, tap: interactive, touchZoom: interactive,
      });
      map.attributionControl.setPrefix("");
      tileRef.current = L.tileLayer(dark ? TILES.dark : TILES.light, { attribution: TILE_ATTR, maxZoom: 20, subdomains: "abcd" }).addTo(map);
      if (interactive) L.control.zoom({ position: "bottomright" }).addTo(map);
      mapRef.current = map;
      setReady(true);
      setTimeout(() => map.invalidateSize(), 120);
      setTimeout(() => map.invalidateSize(), 420);
    };
    tryInit();
    return () => {
      if (raf) cancelAnimationFrame(raf);
      if (mapRef.current) { mapRef.current.remove(); mapRef.current = null; }
    };
    // eslint-disable-next-line
  }, []);

  // keep size correct inside sheets / scaled frame
  React.useEffect(() => {
    if (!ready || !elRef.current) return;
    const ro = new ResizeObserver(() => mapRef.current && mapRef.current.invalidateSize());
    ro.observe(elRef.current);
    return () => ro.disconnect();
  }, [ready]);

  // swap tiles on theme change
  React.useEffect(() => {
    if (!ready || !tileRef.current) return;
    tileRef.current.setUrl(dark ? TILES.dark : TILES.light);
  }, [dark, ready]);

  // car pin
  React.useEffect(() => {
    if (!ready) return;
    const map = mapRef.current;
    if (carSpot) {
      if (!carRef.current) {
        carRef.current = L.marker([carSpot.lat, carSpot.lng], { icon: carPinIcon(emoji), draggable, zIndexOffset: 600 }).addTo(map);
        if (draggable && onPinMove) {
          carRef.current.on("drag", (e) => onPinMove(e.target.getLatLng()));
          carRef.current.on("dragend", (e) => onPinMove(e.target.getLatLng()));
        }
      } else {
        carRef.current.setLatLng([carSpot.lat, carSpot.lng]);
        carRef.current.setIcon(carPinIcon(emoji));
        if (carRef.current.dragging) { draggable ? carRef.current.dragging.enable() : carRef.current.dragging.disable(); }
      }
    } else if (carRef.current) {
      map.removeLayer(carRef.current); carRef.current = null;
    }
  }, [ready, carSpot && carSpot.lat, carSpot && carSpot.lng, emoji, draggable]);

  // me dot + accuracy ring
  React.useEffect(() => {
    if (!ready) return;
    const map = mapRef.current;
    if (me) {
      if (!meRef.current) meRef.current = L.marker([me.lat, me.lng], { icon: meIcon(), interactive: false, zIndexOffset: 400 }).addTo(map);
      else meRef.current.setLatLng([me.lat, me.lng]);
      if (me.accuracy) {
        if (!accRef.current) accRef.current = L.circle([me.lat, me.lng], { radius: me.accuracy, color: "#3b8cff", weight: 1, fillColor: "#3b8cff", fillOpacity: 0.12, interactive: false }).addTo(map);
        else { accRef.current.setLatLng([me.lat, me.lng]); accRef.current.setRadius(me.accuracy); }
      }
    } else {
      if (meRef.current) { map.removeLayer(meRef.current); meRef.current = null; }
      if (accRef.current) { map.removeLayer(accRef.current); accRef.current = null; }
    }
  }, [ready, me && me.lat, me && me.lng, me && me.accuracy]);

  // recenter / fit
  React.useEffect(() => {
    if (!ready) return;
    const map = mapRef.current;
    if (fit && carSpot && me) {
      const b = L.latLngBounds([[carSpot.lat, carSpot.lng], [me.lat, me.lng]]).pad(0.4);
      map.fitBounds(b, { maxZoom: 17, animate: true });
    } else if (center) {
      map.setView([center.lat, center.lng], map.getZoom(), { animate: true });
    }
  }, [ready, fit, center && center.lat, center && center.lng, carSpot && carSpot.lat, me && me.lat]);

  return (
    <div style={{ position: "relative", borderRadius: "var(--radius)", overflow: "hidden", border: "1px solid var(--hairline)", background: "var(--surface-2)", ...style }}>
      <div ref={elRef} style={{ position: "absolute", inset: 0 }} />
    </div>
  );
}

// imperative recenter handle helper (exposes map via ref callback)
Object.assign(window, { LeafletMap, carPinIcon, meIcon });
