/* MANARA — Mapbox map component (NATIVE LAYERS — smooth pan/zoom)
   Uses real Mapbox layers (GeoJSON sources + circle layers) so markers move
   fluidly with the camera. Falls back to FallbackMap on token failure. */

const { useState: useStateMap, useEffect: useEffectMap, useRef: useRefMap } = React;

/* Token comes from /env-config.js (server injects MAPBOX_ACCESS_TOKEN) or any prior script that set window.MAPBOX_TOKEN. */
function getMapboxToken() {
  if (typeof window === 'undefined') return '';
  return String(window.__MAPBOX_PUBLIC_TOKEN__ || window.MAPBOX_TOKEN || '').trim();
}

const STYLES = {
  dark: 'mapbox://styles/mapbox/dark-v11',
  satellite: 'mapbox://styles/mapbox/satellite-streets-v12'
};

/* MANARA brief — UAE-wide executive default, north-up, bounded pan */
const MAP_CONFIG = {
  center: [54.5, 24.2],
  zoom: 7.2,
  pitch: 28,
  bearing: 0,
  maxBounds: [[50.5, 21.5], [57.0, 26.8]]
};

function easeOutQuad(t) {
  return t * (2 - t);
}

/* ============================================================
   Static GeoJSON: motorway corridors + emirate centroids
   Highlighted per scenario to keep map ↔ data coherent
   ============================================================ */
const CORRIDOR_E11 = {
  type: 'Feature',
  properties: { id: 'e11', name: 'E11 — Sheikh Zayed Road' },
  geometry: {
    type: 'LineString',
    // Approximate Abu Dhabi → Dubai → Sharjah → RAK trunk
    coordinates: [
      [54.367, 24.483], [54.430, 24.520], [54.610, 24.620],
      [54.760, 24.720], [54.920, 24.850], [55.050, 24.950],
      [55.180, 25.040], [55.270, 25.200], [55.398, 25.336],
      [55.500, 25.420], [55.700, 25.580], [55.943, 25.789]
    ]
  }
};
const CORRIDOR_E311 = {
  type: 'Feature',
  properties: { id: 'e311', name: 'E311 — Sheikh Mohammed bin Zayed Rd' },
  geometry: {
    type: 'LineString',
    // Abu Dhabi → outer-Dubai → Sharjah → Ajman → RAK
    coordinates: [
      [54.500, 24.430], [54.700, 24.650], [54.880, 24.870],
      [55.050, 25.050], [55.250, 25.220], [55.400, 25.380],
      [55.500, 25.430], [55.620, 25.530], [55.800, 25.680],
      [55.943, 25.789]
    ]
  }
};
const EMIRATE_LABELS_GEO = [
  { id: 'auh', en: 'Abu Dhabi',  ar: 'أبوظبي',     lng: 53.85, lat: 23.50 },
  { id: 'dxb', en: 'Dubai',      ar: 'دبي',         lng: 55.27, lat: 25.05 },
  { id: 'shj', en: 'Sharjah',    ar: 'الشارقة',     lng: 55.55, lat: 25.45 },
  { id: 'ajm', en: 'Ajman',      ar: 'عجمان',       lng: 55.60, lat: 25.55 },
  { id: 'uaq', en: 'Umm Al Quwain', ar: 'أم القيوين', lng: 55.75, lat: 25.65 },
  { id: 'rak', en: 'Ras Al Khaimah', ar: 'رأس الخيمة', lng: 55.95, lat: 25.85 },
  { id: 'fuj', en: 'Fujairah',   ar: 'الفجيرة',     lng: 56.30, lat: 25.30 },
  { id: 'aua', en: 'Al Ain',     ar: 'العين',        lng: 55.76, lat: 24.21 }
];

/* Build a small ring polygon for geofence visualization */
function geofenceRing(lng, lat, radiusKm = 1.5, sides = 64) {
  const coords = [];
  const km2deg = 1 / 110.574;
  for (let i = 0; i <= sides; i++) {
    const a = (i / sides) * Math.PI * 2;
    coords.push([
      lng + Math.cos(a) * radiusKm * km2deg / Math.cos(lat * Math.PI / 180),
      lat + Math.sin(a) * radiusKm * km2deg
    ]);
  }
  return { type: 'Feature', properties: {}, geometry: { type: 'Polygon', coordinates: [coords] } };
}

/* Convert our prop arrays into GeoJSON FeatureCollections */
function corridorsForScenario(scenario) {
  const both = [CORRIDOR_E11, CORRIDOR_E311];
  const tagged = both.map(f => {
    const isActive =
      (scenario?.mapFocus === 'e11' && f.properties.id === 'e11') ||
      (scenario?.mapFocus === 'e311' && f.properties.id === 'e311');
    return { ...f, properties: { ...f.properties, active: isActive ? 1 : 0 } };
  });
  return { type: 'FeatureCollection', features: tagged };
}
function emiratesGeoJSON(locale) {
  return {
    type: 'FeatureCollection',
    features: EMIRATE_LABELS_GEO.map(e => ({
      type: 'Feature',
      properties: { name: locale === 'ar' ? e.ar : e.en },
      geometry: { type: 'Point', coordinates: [e.lng, e.lat] }
    }))
  };
}
function geofenceGeoJSON(scenario) {
  if (!scenario) return { type: 'FeatureCollection', features: [] };
  if (scenario.id === 'hassantuk') {
    return { type: 'FeatureCollection', features: [geofenceRing(55.764, 24.207, 0.6)] };
  }
  if (scenario.id === 'e11' && scenario.mapCoords) {
    return { type: 'FeatureCollection', features: [geofenceRing(scenario.mapCoords.lng, scenario.mapCoords.lat, 1.2)] };
  }
  return { type: 'FeatureCollection', features: [] };
}

/* Convert our prop arrays into GeoJSON FeatureCollections */
function incidentsToGeoJSON(incidents) {
  return {
    type: 'FeatureCollection',
    features: (incidents || []).map((inc, i) => ({
      type: 'Feature',
      id: i,
      properties: {
        severity: inc.severity,
        label: inc.label || '',
        priority: inc.severity === 'critical' ? 'P1' : inc.severity === 'warning' ? 'P2' : 'P3'
      },
      geometry: { type: 'Point', coordinates: [inc.lng, inc.lat] }
    }))
  };
}
function patrolsToGeoJSON(patrols) {
  return {
    type: 'FeatureCollection',
    features: (patrols || []).map((p, i) => ({
      type: 'Feature',
      id: i,
      properties: { heading: p.heading || 0 },
      geometry: { type: 'Point', coordinates: [p.lng, p.lat] }
    }))
  };
}
function opCentersToGeoJSON(opCenters, focusId) {
  return {
    type: 'FeatureCollection',
    features: (opCenters || []).map((c, i) => ({
      type: 'Feature',
      id: i,
      properties: { name: c.name || c.id, focus: c.id === focusId ? 1 : 0 },
      geometry: { type: 'Point', coordinates: [c.lng, c.lat] }
    }))
  };
}

/* Incident density for heatmap (brief — teal → amber → red by weight) */
function heatmapGeoJSON(incidents) {
  const feats = (incidents || []).map((inc) => ({
    type: 'Feature',
    properties: {
      intensity: inc.severity === 'critical' ? 1 : inc.severity === 'warning' ? 0.65 : 0.35
    },
    geometry: { type: 'Point', coordinates: [inc.lng, inc.lat] }
  }));
  const ambient = [
    [55.27, 25.2, 0.25], [54.37, 24.48, 0.22], [55.4, 25.34, 0.2],
    [55.94, 25.79, 0.18], [55.76, 24.21, 0.2], [56.34, 25.13, 0.18]
  ];
  ambient.forEach(([lng, lat, w]) => {
    feats.push({
      type: 'Feature',
      properties: { intensity: w },
      geometry: { type: 'Point', coordinates: [lng, lat] }
    });
  });
  return { type: 'FeatureCollection', features: feats };
}

/* Hassantuk-style residential sensor scatter (brief — subtle blue dots) */
function hassantukSensorsGeoJSON() {
  const hubs = [
    [55.764, 24.207, 10], [55.27, 25.12, 14], [54.37, 24.48, 12],
    [55.4, 25.34, 8], [55.95, 25.79, 6], [56.34, 25.13, 6]
  ];
  const features = [];
  hubs.forEach(([lng, lat, n]) => {
    for (let i = 0; i < n; i++) {
      features.push({
        type: 'Feature',
        properties: {},
        geometry: {
          type: 'Point',
          coordinates: [
            lng + (Math.random() - 0.5) * 0.055,
            lat + (Math.random() - 0.5) * 0.045
          ]
        }
      });
    }
  });
  return { type: 'FeatureCollection', features };
}

/* Tiny inline SVG for the patrol chevron — registered as a Mapbox image */
function makePatrolImage(map) {
  return new Promise((resolve) => {
    const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
      <defs>
        <filter id="g" x="-50%" y="-50%" width="200%" height="200%">
          <feGaussianBlur stdDeviation="1.5" />
        </filter>
      </defs>
      <g filter="url(#g)" opacity="0.7">
        <path d="M 16 4 L 24 26 L 16 22 L 8 26 Z" fill="#00E5CC"/>
      </g>
      <path d="M 16 4 L 24 26 L 16 22 L 8 26 Z" fill="#00E5CC" stroke="#0A1120" stroke-width="1"/>
    </svg>`;
    const img = new Image(32, 32);
    img.onload = () => {
      if (!map.hasImage('manara-patrol')) map.addImage('manara-patrol', img, { sdf: false });
      resolve();
    };
    img.onerror = () => resolve();
    img.src = 'data:image/svg+xml;base64,' + btoa(svg);
  });
}

function MapboxMap({ locale, scenario, incidents, patrols, opCenters, isSatellite, mode }) {
  const containerRef = useRefMap(null);
  const mapRef = useRefMap(null);
  /** Style URI used in `new mapboxgl.Map({ style })` — used to skip one redundant setStyle when `ready` flips true. */
  const styleUriAtMapInitRef = useRefMap(null);
  const [ready, setReady] = useStateMap(false);
  const [errored, setErrored] = useStateMap(false);

  /* ---------- INIT ---------- */
  useEffectMap(() => {
    if (!containerRef.current) return;
    if (typeof mapboxgl === 'undefined') { setErrored(true); return; }
    const MAPBOX_TOKEN = getMapboxToken();
    if (!MAPBOX_TOKEN) { setErrored(true); return; }
    try {
      mapboxgl.accessToken = MAPBOX_TOKEN;
      const initialStyleUri = isSatellite ? STYLES.satellite : STYLES.dark;
      styleUriAtMapInitRef.current = initialStyleUri;
      const map = new mapboxgl.Map({
        container: containerRef.current,
        style: initialStyleUri,
        center: MAP_CONFIG.center,
        zoom: MAP_CONFIG.zoom,
        pitch: MAP_CONFIG.pitch,
        bearing: MAP_CONFIG.bearing,
        maxBounds: MAP_CONFIG.maxBounds,
        attributionControl: false,
        logoPosition: 'bottom-left'
      });
      mapRef.current = map;
      map.on('load', async () => {
        await makePatrolImage(map);
        installLayers(map);
        setReady(true);
      });
      map.on('style.load', async () => {
        // After style swap we need to re-install our sources/layers
        await makePatrolImage(map);
        installLayers(map);
      });
      map.on('error', () => { /* swallow style errors gracefully */ });
      return () => { map.remove(); mapRef.current = null; };
    } catch (e) {
      setErrored(true);
    }
    // eslint-disable-next-line
  }, []);

  /* Install or re-install all sources + layers (idempotent) */
  function installLayers(map) {
    // Sources
    if (!map.getSource('manara-heatmap-data')) {
      map.addSource('manara-heatmap-data', { type: 'geojson', data: heatmapGeoJSON(incidents) });
    }
    if (!map.getSource('manara-hassantuk')) {
      map.addSource('manara-hassantuk', { type: 'geojson', data: hassantukSensorsGeoJSON() });
    }
    if (!map.getSource('manara-incidents')) {
      map.addSource('manara-incidents', {
        type: 'geojson',
        data: incidentsToGeoJSON(incidents),
        cluster: true,
        clusterMaxZoom: 14,
        clusterRadius: 50
      });
    }
    if (!map.getSource('manara-patrols')) {
      map.addSource('manara-patrols', { type: 'geojson', data: patrolsToGeoJSON(patrols) });
    }
    if (!map.getSource('manara-ops')) {
      map.addSource('manara-ops', { type: 'geojson', data: opCentersToGeoJSON(opCenters, scenario?.mapFocus) });
    }
    if (!map.getSource('manara-corridors')) {
      map.addSource('manara-corridors', { type: 'geojson', data: corridorsForScenario(scenario), lineMetrics: true });
    }
    if (!map.getSource('manara-emirates')) {
      map.addSource('manara-emirates', { type: 'geojson', data: emiratesGeoJSON(locale) });
    }
    if (!map.getSource('manara-geofence')) {
      map.addSource('manara-geofence', { type: 'geojson', data: geofenceGeoJSON(scenario) });
    }

    /* ---- HEATMAP + HASSANTUK (brief — density + sensor field under vectors) ---- */
    if (!map.getLayer('manara-heatmap')) {
      map.addLayer({
        id: 'manara-heatmap',
        type: 'heatmap',
        source: 'manara-heatmap-data',
        paint: {
          'heatmap-weight': ['get', 'intensity'],
          'heatmap-intensity': 1,
          'heatmap-radius': 30,
          'heatmap-opacity': isSatellite ? 0.35 : 0.5,
          'heatmap-color': [
            'interpolate', ['linear'], ['heatmap-density'],
            0, 'rgba(0, 0, 0, 0)',
            0.2, 'rgba(0, 229, 204, 0.4)',
            0.5, 'rgba(255, 184, 0, 0.6)',
            0.8, 'rgba(255, 71, 87, 0.8)'
          ]
        }
      });
    }
    if (!map.getLayer('manara-hassantuk-dots')) {
      map.addLayer({
        id: 'manara-hassantuk-dots',
        type: 'circle',
        source: 'manara-hassantuk',
        paint: {
          'circle-radius': 3,
          'circle-color': '#38BDF8',
          'circle-opacity': 0.38,
          'circle-blur': 0.45
        }
      });
    }

    /* ---- CORRIDORS — base + active highlight ---- */
    if (!map.getLayer('manara-corridor-base')) {
      map.addLayer({
        id: 'manara-corridor-base',
        type: 'line',
        source: 'manara-corridors',
        layout: { 'line-cap': 'round', 'line-join': 'round' },
        paint: {
          'line-color': '#00E5CC',
          'line-width': ['interpolate', ['linear'], ['zoom'], 6, 1.5, 12, 3],
          'line-opacity': ['case', ['==', ['get', 'active'], 1], 0.0, 0.18]
        }
      });
    }
    if (!map.getLayer('manara-corridor-active-glow')) {
      map.addLayer({
        id: 'manara-corridor-active-glow',
        type: 'line',
        source: 'manara-corridors',
        filter: ['==', ['get', 'active'], 1],
        layout: { 'line-cap': 'round', 'line-join': 'round' },
        paint: {
          'line-color': ['match', ['get', 'id'], 'e11', '#FF4757', 'e311', '#FFB800', '#00E5CC'],
          'line-width': ['interpolate', ['linear'], ['zoom'], 6, 8, 12, 18],
          'line-opacity': 0.18,
          'line-blur': 4
        }
      });
    }
    if (!map.getLayer('manara-corridor-active')) {
      map.addLayer({
        id: 'manara-corridor-active',
        type: 'line',
        source: 'manara-corridors',
        filter: ['==', ['get', 'active'], 1],
        layout: { 'line-cap': 'round', 'line-join': 'round' },
        paint: {
          'line-color': ['match', ['get', 'id'], 'e11', '#FF4757', 'e311', '#FFB800', '#00E5CC'],
          'line-width': ['interpolate', ['linear'], ['zoom'], 6, 2.5, 12, 5],
          'line-opacity': 0.95
        }
      });
    }
    if (!map.getLayer('manara-corridor-label')) {
      map.addLayer({
        id: 'manara-corridor-label',
        type: 'symbol',
        source: 'manara-corridors',
        layout: {
          'symbol-placement': 'line',
          'text-field': ['get', 'id'],
          'text-font': ['DIN Pro Bold', 'Arial Unicode MS Bold'],
          'text-size': 11,
          'text-letter-spacing': 0.18,
          'symbol-spacing': 220,
          'text-allow-overlap': false,
          'text-transform': 'uppercase'
        },
        paint: {
          'text-color': ['case', ['==', ['get', 'active'], 1], '#FFFFFF', 'rgba(0,229,204,0.7)'],
          'text-halo-color': '#050A12',
          'text-halo-width': 1.5
        }
      });
    }

    /* ---- EMIRATES — major-city labels ---- */
    if (!map.getLayer('manara-emirates-label')) {
      map.addLayer({
        id: 'manara-emirates-label',
        type: 'symbol',
        source: 'manara-emirates',
        layout: {
          'text-field': ['get', 'name'],
          'text-font': ['DIN Pro Bold', 'Arial Unicode MS Bold'],
          'text-size': ['interpolate', ['linear'], ['zoom'], 6, 11, 10, 16],
          'text-letter-spacing': 0.2,
          'text-transform': 'uppercase',
          'text-offset': [0, -0.6],
          'text-allow-overlap': false
        },
        paint: {
          'text-color': 'rgba(241,245,249,0.55)',
          'text-halo-color': '#050A12',
          'text-halo-width': 2
        }
      });
    }

    /* ---- GEOFENCE — scenario-specific containment ring ---- */
    if (!map.getLayer('manara-geofence-fill')) {
      map.addLayer({
        id: 'manara-geofence-fill',
        type: 'fill',
        source: 'manara-geofence',
        paint: { 'fill-color': '#FF4757', 'fill-opacity': 0.06 }
      });
    }
    if (!map.getLayer('manara-geofence-line')) {
      map.addLayer({
        id: 'manara-geofence-line',
        type: 'line',
        source: 'manara-geofence',
        paint: {
          'line-color': '#FF4757',
          'line-width': 1.5,
          'line-opacity': 0.7,
          'line-dasharray': [2, 3]
        }
      });
    }

    // 3D buildings
    if (!map.getLayer('manara-3d-buildings')) {
      try {
        const labelLayer = map.getStyle().layers?.find(l => /label/.test(l.id));
        map.addLayer({
          id: 'manara-3d-buildings',
          source: 'composite',
          'source-layer': 'building',
          type: 'fill-extrusion',
          minzoom: 12,
          paint: {
            'fill-extrusion-color': isSatellite ? '#1a2540' : '#1A2438',
            'fill-extrusion-height': ['get', 'height'],
            'fill-extrusion-base': ['get', 'min_height'],
            'fill-extrusion-opacity': isSatellite ? 0.55 : 0.75
          }
        }, labelLayer?.id);
      } catch (e) { /* ignore */ }
    }

    /* ---- INCIDENTS — clustered + unclustered (MANARA / Panorama brief) ---- */
    const unclustered = ['!', ['has', 'point_count']];
    if (!map.getLayer('manara-clusters')) {
      map.addLayer({
        id: 'manara-clusters',
        type: 'circle',
        source: 'manara-incidents',
        filter: ['has', 'point_count'],
        paint: {
          'circle-color': [
            'step', ['get', 'point_count'],
            '#3B82F6', 10, '#0097A7', 30, '#FFB800'
          ],
          'circle-radius': ['step', ['get', 'point_count'], 18, 10, 24, 30, 32],
          'circle-stroke-width': 2,
          'circle-stroke-color': 'rgba(0, 229, 204, 0.4)'
        }
      });
    }
    if (!map.getLayer('manara-cluster-count')) {
      map.addLayer({
        id: 'manara-cluster-count',
        type: 'symbol',
        source: 'manara-incidents',
        filter: ['has', 'point_count'],
        layout: {
          'text-field': ['to-string', ['get', 'point_count']],
          'text-font': ['DIN Pro Bold', 'Arial Unicode MS Bold'],
          'text-size': 12
        },
        paint: {
          'text-color': '#F1F5F9'
        }
      });
    }
    if (!map.getLayer('manara-incidents-pulse')) {
      map.addLayer({
        id: 'manara-incidents-pulse',
        type: 'circle',
        source: 'manara-incidents',
        filter: ['all', unclustered, ['==', ['get', 'severity'], 'critical']],
        paint: {
          'circle-color': '#FF4757',
          'circle-radius': ['interpolate', ['linear'], ['zoom'], 6, 12, 14, 32],
          'circle-opacity': 0.25,
          'circle-blur': 0.6
        }
      });
    }
    if (!map.getLayer('manara-incidents-ring')) {
      map.addLayer({
        id: 'manara-incidents-ring',
        type: 'circle',
        source: 'manara-incidents',
        filter: unclustered,
        paint: {
          'circle-radius': [
            'match', ['get', 'severity'],
            'critical', 16,
            'warning', 11,
            7
          ],
          'circle-color': 'transparent',
          'circle-stroke-color': [
            'match', ['get', 'severity'],
            'critical', '#FF4757',
            'warning', '#FFB800',
            '#3B82F6'
          ],
          'circle-stroke-width': 2,
          'circle-stroke-opacity': 0.55
        }
      });
    }
    if (!map.getLayer('manara-incidents-core')) {
      map.addLayer({
        id: 'manara-incidents-core',
        type: 'circle',
        source: 'manara-incidents',
        filter: unclustered,
        paint: {
          'circle-radius': [
            'match', ['get', 'severity'],
            'critical', 8,
            'warning', 6,
            4
          ],
          'circle-color': [
            'match', ['get', 'severity'],
            'critical', '#FF4757',
            'warning', '#FFB800',
            '#3B82F6'
          ],
          'circle-stroke-color': '#0A1120',
          'circle-stroke-width': 1.5
        }
      });
    }
    if (!map.getLayer('manara-incidents-label')) {
      map.addLayer({
        id: 'manara-incidents-label',
        type: 'symbol',
        source: 'manara-incidents',
        filter: ['all', unclustered, ['!=', ['get', 'severity'], 'info']],
        layout: {
          'text-field': ['concat', ['get', 'priority'], ' · ', ['get', 'label']],
          'text-font': ['DIN Pro Bold', 'Arial Unicode MS Bold'],
          'text-size': 10,
          'text-offset': [0, -2.0],
          'text-anchor': 'bottom',
          'text-letter-spacing': 0.08,
          'text-allow-overlap': false
        },
        paint: {
          'text-color': [
            'match', ['get', 'severity'],
            'critical', '#FF4757',
            'warning', '#FFB800',
            '#FFFFFF'
          ],
          'text-halo-color': '#050A12',
          'text-halo-width': 1.5
        }
      });
    }

    /* ---- OP CENTERS ---- */
    if (!map.getLayer('manara-ops-glow')) {
      map.addLayer({
        id: 'manara-ops-glow',
        type: 'circle',
        source: 'manara-ops',
        paint: {
          'circle-radius': ['case', ['==', ['get', 'focus'], 1], 18, 10],
          'circle-color': '#00E5CC',
          'circle-opacity': 0.15,
          'circle-blur': 0.7
        }
      });
    }
    if (!map.getLayer('manara-ops-core')) {
      map.addLayer({
        id: 'manara-ops-core',
        type: 'circle',
        source: 'manara-ops',
        paint: {
          'circle-radius': ['case', ['==', ['get', 'focus'], 1], 7, 5],
          'circle-color': '#00E5CC',
          'circle-stroke-color': '#050A12',
          'circle-stroke-width': 2
        }
      });
    }

    /* ---- PATROLS — symbol layer with rotation ---- */
    if (!map.getLayer('manara-patrols')) {
      map.addLayer({
        id: 'manara-patrols',
        type: 'symbol',
        source: 'manara-patrols',
        layout: {
          'icon-image': 'manara-patrol',
          'icon-size': 0.7,
          'icon-rotate': ['get', 'heading'],
          'icon-allow-overlap': true,
          'icon-rotation-alignment': 'map'
        }
      });
    }
  }

  /* ---------- STYLE SWITCH ----------
     Avoid calling setStyle once with the same URI the map was just built with:
     that forces an unnecessary full style reload and flashes / drops custom layers. */
  useEffectMap(() => {
    if (!mapRef.current || !ready) return;
    const target = isSatellite ? STYLES.satellite : STYLES.dark;
    const initUri = styleUriAtMapInitRef.current;
    if (initUri !== null && initUri === target) {
      styleUriAtMapInitRef.current = null;
      return;
    }
    styleUriAtMapInitRef.current = null;
    mapRef.current.setStyle(target);
  }, [isSatellite, ready]);

  /* ---------- DATA UPDATES (no marker DOM thrash) ---------- */
  useEffectMap(() => {
    const map = mapRef.current;
    if (!map || !ready) return;
    const inc = incidentsToGeoJSON(incidents);
    const src = map.getSource('manara-incidents');
    if (src) src.setData(inc);
    const hm = map.getSource('manara-heatmap-data');
    if (hm) hm.setData(heatmapGeoJSON(incidents));
  }, [incidents, ready]);

  /* Brief: satellite imagery reads through heatmap */
  useEffectMap(() => {
    const map = mapRef.current;
    if (!map || !ready || !map.getLayer('manara-heatmap')) return;
    try {
      map.setPaintProperty('manara-heatmap', 'heatmap-opacity', isSatellite ? 0.35 : 0.5);
    } catch (e) { /* style swap in progress */ }
  }, [isSatellite, ready]);

  useEffectMap(() => {
    const map = mapRef.current;
    if (!map || !ready) return;
    const src = map.getSource('manara-patrols');
    if (src) src.setData(patrolsToGeoJSON(patrols));
  }, [patrols, ready]);

  useEffectMap(() => {
    const map = mapRef.current;
    if (!map || !ready) return;
    const src = map.getSource('manara-ops');
    if (src) src.setData(opCentersToGeoJSON(opCenters, scenario?.mapFocus));
  }, [opCenters, scenario, ready]);

  /* ---------- Corridor + emirate + geofence data sync ---------- */
  useEffectMap(() => {
    const map = mapRef.current;
    if (!map || !ready) return;
    const corridors = map.getSource('manara-corridors');
    if (corridors) corridors.setData(corridorsForScenario(scenario));
    const fence = map.getSource('manara-geofence');
    if (fence) fence.setData(geofenceGeoJSON(scenario));
  }, [scenario, ready]);

  useEffectMap(() => {
    const map = mapRef.current;
    if (!map || !ready) return;
    const emr = map.getSource('manara-emirates');
    if (emr) emr.setData(emiratesGeoJSON(locale));
  }, [locale, ready]);

  /* ---------- Animated flow on active corridor (line-dasharray cycle) ---------- */
  useEffectMap(() => {
    const map = mapRef.current;
    if (!map || !ready) return;
    let raf;
    const dashSequence = [
      [0, 4, 3], [0.5, 4, 2.5], [1, 4, 2], [1.5, 4, 1.5],
      [2, 4, 1], [2.5, 4, 0.5], [3, 4, 0], [3.5, 3.5, 0],
      [4, 3, 0], [4, 2.5, 0.5], [4, 2, 1], [4, 1.5, 1.5],
      [4, 1, 2], [4, 0.5, 2.5], [4, 0, 3], [3.5, 0, 3.5]
    ];
    let i = 0, last = 0;
    const tick = (ts) => {
      if (!mapRef.current) return;
      if (ts - last > 80) {
        try {
          if (map.getLayer('manara-corridor-active')) {
            map.setPaintProperty('manara-corridor-active', 'line-dasharray', dashSequence[i]);
          }
        } catch (e) {}
        i = (i + 1) % dashSequence.length;
        last = ts;
      }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => raf && cancelAnimationFrame(raf);
  }, [ready]);

  /* ---------- CINEMATIC FLY-TO (brief: steady 10s / crisis lock / scenario focus) ---------- */
  useEffectMap(() => {
    const map = mapRef.current;
    if (!map || !ready) return;

    if (mode === 'crisis') {
      const crit = (incidents || []).find((i) => i.severity === 'critical');
      const lng = scenario?.mapCoords
        ? scenario.mapCoords.lng
        : (crit ? crit.lng : MAP_CONFIG.center[0]);
      const lat = scenario?.mapCoords
        ? scenario.mapCoords.lat
        : (crit ? crit.lat : MAP_CONFIG.center[1]);
      map.flyTo({
        center: [lng, lat],
        zoom: 11.5,
        pitch: 48,
        bearing: 0,
        duration: 5500,
        curve: 1.42,
        essential: true,
        easing: easeOutQuad
      });
      return undefined;
    }

    if (scenario && scenario.mapCoords) {
      map.flyTo({
        center: [scenario.mapCoords.lng, scenario.mapCoords.lat],
        zoom: 10.4,
        pitch: 50,
        bearing: 0,
        duration: 5200,
        curve: 1.42,
        essential: true,
        easing: easeOutQuad
      });
      return undefined;
    }

    if (mode !== 'steady') {
      return undefined;
    }

    const targets = (opCenters && opCenters.length) ? opCenters : [];
    const tick = () => {
      if (!mapRef.current || !targets.length) return;
      const t = targets[Math.floor(Math.random() * targets.length)];
      mapRef.current.flyTo({
        center: [t.lng, t.lat],
        zoom: 11 + Math.random() * 1.5,
        pitch: 30 + Math.random() * 20,
        bearing: -10 + Math.random() * 20,
        duration: 6000,
        curve: 1.42,
        essential: true,
        easing: easeOutQuad
      });
    };
    tick();
    const id = setInterval(tick, 10000);
    return () => clearInterval(id);
  }, [scenario, ready, opCenters, mode, incidents]);

  if (errored) {
    return <FallbackMap locale={locale} focus={scenario?.mapFocus} incidents={incidents} patrols={patrols} scenario={scenario} opCenters={opCenters} />;
  }

  return (
    <div style={{ position: 'absolute', inset: 0 }}>
      <div ref={containerRef} style={{ position: 'absolute', inset: 0 }} />
      <div className="map-vignette" aria-hidden="true" />
    </div>
  );
}

window.MapboxMap = MapboxMap;
