'use strict';

const WS_URL = `ws://${window.location.hostname}:5503/ws`;
let ws = null;
let alertCount = 0;

// ── Deduplicación: una entrada por ayuda+tipo mientras no se ACK ──────────
// key = `${tipo}__${aid_id}`  →  { itemEl, ackDone }
const activeAlerts = new Map();

// ── Sonido de alerta (Web Audio API, sin archivos externos) ───────────────
let audioCtx = null;
let beepInterval = null;

function getAudioCtx() {
  if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
  return audioCtx;
}

function beep(freq = 880, duration = 0.12) {
  try {
    const ctx  = getAudioCtx();
    const osc  = ctx.createOscillator();
    const gain = ctx.createGain();
    osc.connect(gain);
    gain.connect(ctx.destination);
    osc.frequency.value = freq;
    osc.type = 'sine';
    gain.gain.setValueAtTime(0.35, ctx.currentTime);
    gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + duration);
    osc.start(ctx.currentTime);
    osc.stop(ctx.currentTime + duration);
  } catch {}
}

function startBeeping(isAlarm) {
  stopBeeping();
  beep(isAlarm ? 1100 : 780);
  beepInterval = setInterval(() => beep(isAlarm ? 1100 : 780), isAlarm ? 1800 : 3000);
}

function stopBeeping() {
  if (beepInterval) { clearInterval(beepInterval); beepInterval = null; }
}

// ── WebSocket ─────────────────────────────────────────────────────────────
function connect() {
  ws = new WebSocket(WS_URL);

  ws.onopen = () => {
    const el = document.getElementById('ws-status');
    el.textContent = 'ONLINE';
    el.className = 'link-indicator online';
  };

  ws.onclose = () => {
    const el = document.getElementById('ws-status');
    el.textContent = 'OFFLINE';
    el.className = 'link-indicator offline';
    setTimeout(connect, 3000);
  };

  ws.onerror = () => ws.close();

  ws.onmessage = (evt) => {
    try { handleMessage(JSON.parse(evt.data)); }
    catch(e) { console.error('WS parse error', e); }
  };
}

// Live ATON telemetry store: mmsi → data object
window.atonData = {};

function handleMessage(msg) {
  switch (msg.type) {
    case 'init':
      (msg.aids    || []).forEach(window.updateAid);
      (msg.vessels || []).forEach(window.updateVessel);
      (msg.atons   || []).forEach(updateAton);
      break;
    case 'vessel':       window.updateVessel(msg); break;
    case 'aid_position': window.updateAid(msg);    break;
    case 'alert':        addEvent(msg);             break;
    case 'gps':          updateGpsStatus(msg);      break;
    case 'aton':         updateAton(msg);           break;
  }
}

function updateAton(data) {
  if (!data.mmsi) return;
  window.atonData[data.mmsi] = data;

  // If this ATON's panel is currently open, refresh it
  const panel = document.getElementById('info-content');
  if (panel && panel.dataset.mmsi === data.mmsi) {
    // Find the aid entry that matches this MMSI and re-render
    const feat = window.aidsSource?.getFeatures()
      .find(f => f.get('mmsi') === data.mmsi);
    if (feat) window.refreshInfoPanel?.(feat.getProperties());
  }

  // Trigger off-position alert if flagged
  if (data.off_position) {
    addEvent({
      tipo:      'ALERTA_AMARILLA',
      subtipo:   'ATON_FUERA_POSICION',
      aid_id:    data.mmsi,
      desplazamiento_m: null,
      timestamp: data.last_update,
    });
  }
  if (data.battery_low) {
    addEvent({
      tipo:      'ALERTA_AMARILLA',
      subtipo:   'ATON_BATERIA_BAJA',
      aid_id:    data.mmsi,
      desplazamiento_m: null,
      timestamp: data.last_update,
    });
  }
}

function addEvent(alert) {
  const needsAck = ['ALERTA_ROJA','ALERTA_AMARILLA'].includes(alert.tipo);
  const dedupeKey = needsAck ? `${alert.tipo}__${alert.aid_id}` : null;

  // Si ya existe entrada para este par tipo+ayuda → solo actualizar detalle, nunca repetir
  if (dedupeKey && activeAlerts.has(dedupeKey)) {
    const entry = activeAlerts.get(dedupeKey);
    const detailEl = entry.itemEl.querySelector('.ev-detail');
    if (detailEl && alert.desplazamiento_m != null)
      detailEl.innerHTML = `${alert.aid_id} &mdash; ${alert.desplazamiento_m} m from nominal`;
    return;
  }

  alertCount++;
  const badge = document.getElementById('alert-badge');
  badge.textContent = alertCount;
  badge.classList.remove('hidden');

  let cls = 'ev-blue', typeLabel = '', detail = '';

  if (alert.tipo === 'ALERTA_ROJA') {
    cls = 'ev-red'; typeLabel = 'CRITICAL — MOVEMENT DETECTED';
    detail = `Aid: ${alert.aid_id}`;
  } else if (alert.tipo === 'ALERTA_AMARILLA') {
    cls = 'ev-yellow'; typeLabel = 'WARNING — DISPLACED';
    detail = `${alert.aid_id} &mdash; ${alert.desplazamiento_m} m from nominal`;
  } else if (alert.tipo === 'GRABACION_INICIADA') {
    cls = 'ev-red'; typeLabel = 'REC STARTED';
    detail = `<span class="ev-mmsi">${alert.mmsi}</span> &rarr; ${alert.aid_nombre}<br>${alert.distancia_m} m &mdash; ${alert.trigger}`;
  } else if (alert.tipo === 'GRABACION_FINALIZADA') {
    cls = 'ev-blue'; typeLabel = 'REC CLOSED';
    detail = `<span class="ev-mmsi">${alert.mmsi}</span> &mdash; Min dist: ${alert.distancia_min_m} m`;
  }

  const time  = new Date().toUTCString().slice(17, 25);
  const aidId = alert.aid_id || null;

  const item = document.createElement('div');
  item.className = `event-item ${cls}`;
  // Persist the raw alert on the DOM so the REPORT modal can read it later.
  // Stable id: prefer backend-emitted uuid, fall back to client-generated.
  const alertId = alert.id || `cli-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;
  item.dataset.alertId = alertId;
  item.dataset.alertJson = JSON.stringify({...alert, id: alertId});
  item.innerHTML = `
    <div class="ev-header">
      <span class="ev-type">${typeLabel}</span>
      <span class="ev-time">${time} UTC</span>
    </div>
    <div class="ev-detail">${detail}</div>
    <div class="ev-actions">
      ${needsAck ? `<button class="ev-ack-btn">ACKNOWLEDGE</button>` : ''}
      <button class="ev-report-btn" onclick="window.openReportModal(this.closest('.event-item'))">REPORT</button>
    </div>
    <div class="ev-reported hidden"></div>
  `;

  if (needsAck) {
    // Símbolo en carta
    const aidFeature = window.aidsSource?.getFeatureById(aidId);
    if (aidFeature) {
      const level = alert.tipo === 'ALERTA_ROJA' ? 'alarm' : 'warning';
      window.setAidWarning?.(aidFeature, level);
    }

    // Pitido
    startBeeping(alert.tipo === 'ALERTA_ROJA');

    // Fila titila hasta ACK
    item.classList.add('ev-blinking');

    // Registrar en mapa de activos
    const entry = { itemEl: item, ackDone: false };
    if (dedupeKey) activeAlerts.set(dedupeKey, entry);

    item.querySelector('.ev-ack-btn').addEventListener('click', function() {
      const ts = new Date().toUTCString().slice(17, 25);
      this.textContent = `ACK — ${ts} — ${window.Auth?.session?.nombre || '?'}`;
      this.disabled = true;
      this.classList.add('ev-ack-done');
      entry.ackDone = true;
      item.classList.remove('ev-blinking');

      // Parar pitido si no quedan alarmas sin ACK
      const anyPending = [...activeAlerts.values()].some(e => !e.ackDone);
      if (!anyPending) stopBeeping();

      // Si la condición ya se resolvió: limpiar entrada y símbolo en carta
      const feat = window.aidsSource?.getFeatureById(aidId);
      const resolved = feat && feat.get('en_posicion') === true && !feat.get('en_movimiento');
      if (resolved) {
        if (dedupeKey) activeAlerts.delete(dedupeKey);
        window.setAidWarning?.(feat, null);
      }
    });
  }

  const list = document.getElementById('events-list');
  list.insertBefore(item, list.firstChild);
  while (list.children.length > 60) list.removeChild(list.lastChild);
}

window.activeAlerts = activeAlerts;

function updateGpsStatus(fix) {
  const dot = document.getElementById('sb-dot-gps');
  const lbl = document.getElementById('sb-gps');
  if (fix.status === 'FIX' && fix.lat != null) {
    if (dot) dot.className = 'sb-dot green';
    if (lbl) {
      const hdop = fix.hdop != null ? `  HDOP ${fix.hdop.toFixed(1)}` : '';
      lbl.textContent = `GPS: ${fix.lat.toFixed(4)}, ${fix.lon.toFixed(4)}${hdop}`;
    }
    if (window.updateOwnShip) window.updateOwnShip(fix);
  } else {
    if (dot) dot.className = 'sb-dot yellow';
    if (lbl) lbl.textContent = 'GPS: CONNECTED — NO FIX';
  }
}

connect();
