/* the turn — MapLibre GL JS map with OpenFreeMap vector tiles.
   Real OSM coastline at any zoom (Walker Bay actually shaped right), place
   names, roads as orientation. Free vector tiles from openfreemap.org, no API
   key. Markers placed at audited per-area lat/lng. */

// Each coord snapped to LAND via point-in-polygon test against Natural Earth
// 10m South Africa polygon. 10 of 25 needed nudging (50-800m inland) because
// the OSM Nominatim returns landed sea-side of the simplified coastline.
// Agulhas left at the lighthouse coord since the cape is too thin for 10m
// (renders fine on the live OSM tiles which have full detail).
const TURN_COORDS = {
  // Walker Bay + Overberg coast (Hermanus-anchored)
  klein:         [-34.4330, 19.3189],
  hermanuscliff: [-34.4082, 19.2613],
  voelklip:      [-34.4222, 19.2811],
  onrus:         [-34.4122, 19.1700],
  dieplaat:      [-34.5825, 19.3225],
  stanford:      [-34.4394, 19.4545],
  hawston:       [-34.3792, 19.1394],
  hangklip:      [-34.3823, 18.8281],
  rooiels:       [-34.3013, 18.8167],
  pringle:       [-34.3499, 18.8337],
  bettys:        [-34.3536, 18.9036],
  palmiet:       [-34.3415, 18.9802],
  botriver:      [-34.3439, 19.1172],
  kelders:       [-34.5572, 19.3650],
  gansbaai:      [-34.5828, 19.3522],
  kleinbaai:     [-34.6149, 19.4184],
  uilenkraal:    [-34.6036, 19.4083],
  franskraal:    [-34.5731, 19.4109],
  dangerpt:      [-34.6304, 19.3025],
  pearly:        [-34.6673, 19.5038],
  quoin:         [-34.7691, 19.6616],
  arniston:      [-34.6681, 20.2241],
  dehoop:        [-34.4454, 20.6022],
  struisbaai:    [-34.8016, 20.0541],
  agulhas:       [-34.8333, 19.9999],
  theewater:     [-34.0330, 19.2477],

  // Eastward (Breede / Stilbaai)
  breede:        [-34.4055, 20.8419],
  stilbaai:      [-34.3650, 21.4133],

  // False Bay arc
  strand:        [-34.1342, 18.8200],
  gordonsbay:    [-34.1626, 18.8576],
  capepoint:     [-34.2961, 18.4870],
  sandvlei:      [-34.0833, 18.4833],

  // Cape Peninsula / Atlantic / West Coast
  houtbay:       [-34.0431, 18.3492],
  tablebay:      [-33.8011, 18.4639],
  yzerfontein:   [-33.3406, 18.1572],
  langebaan:     [-33.0917, 18.0376],

  // Inland fresh
  voelvlei:      [-33.3625, 19.0000],
  brandvlei:     [-33.7167, 19.3667],
};

// The engine emits long-form area ids (e.g. 'hermanus-klein-river-lagoon');
// TURN_COORDS keys are short slugs. Bridge them. One entry per known engine area id.
const LONG_TO_SHORT = {
  'hermanus-klein-river-lagoon':           'klein',
  'walker-bay-die-plaat':                  'dieplaat',
  'bot-kleinmond-palmiet':                 'palmiet',
  'de-kelders-klipgat-galjoenbank':        'kelders',
  'uilkraalsmond-franskraal-danger-point': 'dangerpt',
  'breede-witsand-infanta':                'breede',
  'theewaterskloof-dam':                   'theewater',
  'hermanus-onrus-vermont-sandbaai':       'onrus',
  'struisbaai-agulhas-arniston-de-mond':   'struisbaai',
  'langebaan-saldanha-lagoon':             'langebaan',
  'brandvlei-kwaggaskloof':                'brandvlei',
  'false-bay-north-beaches':               'strand',
  'pearly-die-dam-quoin-brandfontein':     'pearly',
  'table-bay-blouberg-melkbos':            'tablebay',
  'voelvlei-misverstand-berg':             'voelvlei',
  'yzerfontein-sixteen-mile':              'yzerfontein',
  'hawston-fisherhaven-bot-west':          'hawston',
  'hermanus-grotto-voelklip-walker-bay-west': 'voelklip',
  'sandvlei-zeekoevlei-urban-fresh':       'sandvlei',
  'stilbaai-goukou-borderline':            'stilbaai',
  'bettys-pringle-rooi-els':               'bettys',
  'cape-peninsula-tmnp':                   'capepoint',
  'hout-bay-atlantic-peninsula':           'houtbay',
  'kogel-steenbras-gordons-bay-strand':    'gordonsbay',
};

function AfricaMap({ areas, onArea }) {
  const { useEffect, useRef } = React;
  const containerRef = useRef(null);
  const mapRef = useRef(null);

  // Resolve area → lat/lng. Tries (in order):
  //   1. explicit a.lat/a.lng on the area object
  //   2. TURN_COORDS keyed by a.id (works for prototype short ids)
  //   3. LONG_TO_SHORT alias map → TURN_COORDS (the real engine emits long ids)
  function areaCoord(a) {
    if (typeof a.lat === 'number' && typeof a.lng === 'number') return [a.lng, a.lat];
    const direct = TURN_COORDS[a.id];
    if (direct) return [direct[1], direct[0]];
    const aliased = LONG_TO_SHORT[a.id];
    if (aliased && TURN_COORDS[aliased]) return [TURN_COORDS[aliased][1], TURN_COORDS[aliased][0]];
    return null;
  }

  useEffect(() => {
    if (!containerRef.current || mapRef.current || !window.maplibregl) return;

    const map = new window.maplibregl.Map({
      container: containerRef.current,
      style: 'https://tiles.openfreemap.org/styles/positron',
      // Initial framing covers Cape Peninsula → Stilbaai, the real engine's
      // 24-area footprint. fitBounds() in 'load' below refines to actual markers.
      center: [19.6, -34.0],
      zoom: 7,
      attributionControl: { compact: true },
      hash: false,
    });
    mapRef.current = map;

    map.on('styledata', () => {
      // Minimal style: land + water + faint country borders. Strip everything
      // else (roads, buildings, towns, parks, place labels) so the spots are
      // the only foreground objects, per the brief: "the map is bespoke...
      // spots are the only colourful objects".
      const recolor = (id, prop, val) => {
        try { map.setPaintProperty(id, prop, val); } catch (_) {}
      };
      const hide = (id) => {
        try { map.setLayoutProperty(id, 'visibility', 'none'); } catch (_) {}
      };

      // somewhere.rivett.tech palette. background = LAND colour, water = sunk.
      recolor('background', 'background-color', '#00524E');  // somewhere --green-800
      recolor('water', 'fill-color', '#042A28');             // somewhere --green-950
      recolor('boundary_2', 'line-color', 'rgba(245,248,248,0.08)');

      // Strip the noise
      [
        'park', 'landcover_ice_shelf', 'landcover_glacier',
        'landuse_residential', 'landcover_wood',
        'waterway', 'building',
        'tunnel_motorway_casing', 'tunnel_motorway_inner',
        'aeroway-taxiway', 'aeroway-runway-casing', 'aeroway-area', 'aeroway-runway',
        'road_area_pier', 'road_pier',
        'highway_path', 'highway_minor', 'highway_major_casing', 'highway_major_inner',
        'highway_major_subtle', 'highway_motorway_casing', 'highway_motorway_inner',
        'highway_motorway_subtle',
        'railway_transit', 'railway_transit_dashline', 'railway_service',
        'railway_service_dashline', 'railway', 'railway_dashline',
        'highway_motorway_bridge_casing', 'highway_motorway_bridge_inner',
        'boundary_3', 'boundary_disputed',
        'waterway_line_label', 'water_name_point_label', 'water_name_line_label',
        'highway-name-path', 'highway-name-minor', 'highway-name-major',
        'highway-shield-non-us', 'highway-shield-us-interstate', 'road_shield_us',
        'airport',
        'label_other', 'label_village', 'label_town', 'label_state',
        'label_city', 'label_city_capital',
        'label_country_3', 'label_country_2', 'label_country_1',
      ].forEach(hide);
    });

    map.on('load', () => {

      // After markers are placed, fit the viewport to the actual coords so
      // every area is visible regardless of how the engine's footprint shifts.
      const bounds = new window.maplibregl.LngLatBounds();
      let extended = 0;
      areas.forEach((a) => {
        const c = areaCoord(a);
        if (c) { bounds.extend(c); extended++; }
      });
      if (extended > 1) {
        map.fitBounds(bounds, { padding: { top: 30, bottom: 60, left: 30, right: 30 }, duration: 0, maxZoom: 9.5 });
      }

      // Drop verdict-coloured markers for each area
      areas.forEach((a) => {
        const lngLat = areaCoord(a);
        if (!lngLat) return;
        const verdict = a.today?.verdict || 'skip';
        const color =
          verdict === 'go'    ? '#BCF44C' :   // somewhere --lime-500
          verdict === 'scout' ? '#B9BE8E' :   // somewhere --sage-500
                                '#9AA4A1';   // somewhere --ink-400
        const conf = a.today?.confidence || 'high';

        // Build a custom DOM marker (so we can match design language - solid
        // dot for high confidence, hollow ring for low).
        const el = document.createElement('button');
        el.style.cssText = `
          width: 16px; height: 16px; border-radius: 50%; cursor: pointer;
          background: ${conf === 'low' ? 'transparent' : color};
          border: ${conf === 'low' ? `2px dashed ${color}` : `2px solid ${color}`};
          box-shadow: ${verdict === 'go' && conf === 'high'
            ? `0 0 0 1px rgba(188,244,76,.35), 0 0 14px rgba(188,244,76,.5)`
            : `0 0 0 1.5px #013A3D`};
          padding: 0;
        `;
        el.title = a.name;
        el.addEventListener('click', (e) => {
          e.stopPropagation();
          onArea?.(a.id);
        });

        const popup = new window.maplibregl.Popup({
          offset: 14,
          closeButton: false,
          closeOnClick: true,
          className: 'turn-popup',
        }).setHTML(`
          <div style="
            font-family: 'Space Grotesk', sans-serif;
            background: #00524E; color: #F5F8F8;
            padding: 8px 12px; border-radius: 10px;
            border: 1px solid #0A6660;
            font-size: 13px; font-weight: 600;
            white-space: nowrap;
          ">${a.name}</div>
        `);

        new window.maplibregl.Marker({ element: el })
          .setLngLat(lngLat)
          .setPopup(popup)
          .addTo(map);
      });
    });

    map.addControl(new window.maplibregl.NavigationControl({ showCompass: false }), 'top-right');

    return () => {
      map.remove();
      mapRef.current = null;
    };
  }, []);

  return (
    <div style={{ position: 'relative', borderRadius: 'var(--r-md)', overflow: 'hidden', border: '1px solid var(--border)', height: 480 }}>
      <div ref={containerRef} style={{ position: 'absolute', inset: 0 }} />
      <div style={{
        position: 'absolute', left: 10, right: 10, bottom: 10, zIndex: 1,
        display: 'flex', alignItems: 'center', gap: 12, padding: '8px 12px',
        background: 'rgba(12,59,50,0.85)', backdropFilter: 'blur(10px)',
        border: '1px solid var(--hairline-bold)', borderRadius: 'var(--r-md)',
        pointerEvents: 'none',
      }}>
        <MapLegend color="var(--verdict-go)" label="go" />
        <MapLegend color="var(--verdict-worth)" label="scout" />
        <MapLegend color="var(--verdict-dont)" label="skip" />
        <span style={{ marginLeft: 'auto', fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.06em', color: 'var(--text-label)' }}>
          osm · openfreemap
        </span>
      </div>
    </div>
  );
}

function MapLegend({ color, label }) {
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-dim)', letterSpacing: '0.04em' }}>
      <span style={{ width: 8, height: 8, borderRadius: '50%', background: color }} />
      {label}
    </span>
  );
}

window.AfricaMap = AfricaMap;
