
/* FICON-X Airport Operations — independent runway status overlay */
(() => {
  'use strict';

  const SOURCE = 'ops-runway-status-data';
  const LAYER_HALO = 'ops-runway-status-halo';
  const LAYER = 'ops-runway-status-closed';

  let geometry = null;
  let closed = [];
  let feedAvailable = false;
  let initializedMap = null;
  let rccReports = [];

  const RCC_SOURCE = 'ops-runway-rcc-data';
  const RCC_LAYER = 'ops-runway-rcc-labels';

  function validRcc(value) {
    return Array.isArray(value) &&
      value.length === 3 &&
      value.every(n => Number.isInteger(n) && n >= 0 && n <= 6);
  }

  function rccFeatures() {
    if (!geometry || !feedAvailable) return [];

    const features = [];

    for (const runway of geometry.features) {
      const ends = runway.properties.ends || [];

      // Never cover a published runway closure with an RCC label.
      if (ends.some(end => closed.includes(normalize(end)))) continue;

      const candidates = rccReports.filter(report => {
        if (!validRcc(report.ficon_values)) return false;

        // A single reported runway end establishes RCC direction.
        // Reciprocal runway reports are excluded until direction is verified.
        const reported = normalize(report.runway);
        return !reported.includes('/') &&
          reported === normalize(ends[0]);
      });

      if (candidates.length !== 1) continue;

      const coords = runway.geometry?.coordinates;
      if (!Array.isArray(coords) || coords.length < 2) continue;

      const a = coords[0];
      const b = coords[coords.length - 1];
      const report = candidates[0];

      features.push({
        type:'Feature',
        geometry:{
          type:'Point',
          coordinates:[
            (a[0] + b[0]) / 2,
            (a[1] + b[1]) / 2
          ]
        },
        properties:{
          runway:String(report.runway),
          rcc:report.ficon_values.join('/'),
          conditions:(report.condition_types || []).join(', '),
          coverage:report.coverage_pct ?? '',
          slippery:!!report.slippery_when_wet
        }
      });
    }

    return features;
  }

  function installRcc(map) {
    const collection = {
      type:'FeatureCollection',
      features:rccFeatures()
    };

    const existing = map.getSource(RCC_SOURCE);

    if (existing) existing.setData(collection);
    else map.addSource(RCC_SOURCE, {
      type:'geojson',
      data:collection
    });

    if (!map.getLayer(RCC_LAYER)) {
      map.addLayer({
        id:RCC_LAYER,
        type:'symbol',
        source:RCC_SOURCE,
        layout:{
          'text-field':['get','rcc'],
          'text-size':13,
          'text-font':['Open Sans Bold','Arial Unicode MS Bold'],
          'text-allow-overlap':false
        },
        paint:{
          'text-color':'#ffffff',
          'text-halo-color':'#142333',
          'text-halo-width':2
        }
      });
    }
  }

  const normalize = s => String(s || '').trim().toUpperCase()
    .replace(/^RWY\s*/, '')
    .padStart(3, '0');

  function activeFeatures() {
    if (!geometry || !feedAvailable) return [];

    return geometry.features.filter(feature => {
      const ends = feature.properties.ends || [];
      return ends.some(end => closed.includes(normalize(end)));
    });
  }

  function install() {
    const map = airportMap;

    if (!map || !map.isStyleLoaded() || !geometry) return;

    const collection = {
      type: 'FeatureCollection',
      features: activeFeatures()
    };

    const existing = map.getSource(SOURCE);

    if (existing) {
      existing.setData(collection);
    } else {
      map.addSource(SOURCE, {type:'geojson',data:collection});
    }

    if (!map.getLayer(LAYER_HALO)) {
      map.addLayer({
        id:LAYER_HALO,
        type:'line',
        source:SOURCE,
        layout:{'line-cap':'round','line-join':'round'},
        paint:{
          'line-color':'#541b20',
          'line-width':15,
          'line-opacity':1
        }
      });
    }

    if (!map.getLayer(LAYER)) {
      map.addLayer({
        id:LAYER,
        type:'line',
        source:SOURCE,
        layout:{'line-cap':'round','line-join':'round'},
        paint:{
          'line-color':'#d94a50',
          'line-width':9
        }
      });
    }

    if (initializedMap !== map) {
      initializedMap = map;

      map.on('click',LAYER,e => {
        const feature = e.features?.[0];
        if (!feature) return;

        const runway = String(feature.properties?.runway || '');

        new mapboxgl.Popup({maxWidth:'320px'})
          .setLngLat(e.lngLat)
          .setHTML(
            '<strong>RUNWAY '+runway.replace(/[^0-9A-Z/]/g,'')+'</strong>'+
            '<p>Published runway closure reported by FICON-X.</p>'+
            '<small>Verify current FAA NOTAMs before operational use.</small>'
          )
          .addTo(map);
      });
    }

    installRcc(map);

    console.info(
      'FICON-X runway status:',
      collection.features.length,
      'physical runways closed'
    );
  }

  async function refresh() {
    try {
      const response = await fetch('/api/airport',{cache:'no-store'});
      if (!response.ok) throw new Error('HTTP '+response.status);

      const payload = await response.json();
      const notams = payload.sources?.notams;

      if (!notams?.available) throw new Error('NOTAM feed unavailable');

      const identifiers = notams.data?.closed_runways?.KORD;

      if (!Array.isArray(identifiers)) {
        throw new Error('Closed-runway list unavailable');
      }

      closed = identifiers.map(normalize);
      feedAvailable = true;

      // A successful feed response replaces the prior RCC snapshot.
      const ficon = notams.data?.ficon_data?.KORD;
      rccReports = Array.isArray(ficon) ? ficon : [];
    } catch(error) {
      console.warn(
        'Runway closure feed unavailable — retaining last known status; verify NOTAM currency:',
        error
      );
      // Never interpret a failed feed as confirmation that
      // previously closed runways have reopened.
      // Keep feedAvailable and closed unchanged.
    }

    install();
  }

  async function start() {
    try {
      const response = await fetch('/assets/kord-runways.geojson');
      if (!response.ok) throw new Error('Geometry HTTP '+response.status);

      geometry = await response.json();

      if (geometry.features?.length !== 8) {
        throw new Error('Expected eight physical runways');
      }

      await refresh();

      window.addEventListener('ficon-ops-map-ready',install);

      // Style changes recreate Mapbox layers.
      // The existing map-ready event reinstalls this independent overlay.
      setInterval(refresh,90000);
    } catch(error) {
      console.error('Runway overlay initialization failed:',error);
    }
  }

  start();
})();
