'use strict';
/* Sky plot (azimuth/elevation) + SNR signal bars.
   Mode-aware: lee data-mode del <html> y ajusta colores del canvas.
   HiDPI-aware: escala internamente por devicePixelRatio.
   Labels HTML: todo el texto se pone en divs overlay para máxima nitidez.
   Usage: SkyPlot.update(sats)  donde sats = [{prn,system,el,az,snr,used}, ...] */

const SkyPlot = (function () {

  /* Colores base por sistema */
  const SYS_COLOR = {
    GPS:     '#00c8e8',
    GLONASS: '#f45050',
    Galileo: '#28d870',
    BeiDou:  '#f89030',
    GNSS:    '#a070f8',
    QZSS:    '#f8c820',
  };

  const THEMES = {
    day: {
      bg:          '#0a1628',
      ring:        '#1e3a58',
      ring2:       '#0e2040',
      label:       '#4878a8',
      cardinal:    '#5888b8',
      snrBg:       '#0a1628',
      snrLabel:    '#486888',
      unusedAlpha: '55',
      satText:     '#e0f0ff',
      satTextDim:  '#3868a0',
      snrUsedText: '#c0deff',
      snrDimText:  '#3868a0',
    },
    dusk: {
      bg:          '#050912',
      ring:        '#12202e',
      ring2:       '#080e18',
      label:       '#304060',
      cardinal:    '#3a5070',
      snrBg:       '#050912',
      snrLabel:    '#283848',
      unusedAlpha: '44',
      satText:     '#b0c8e0',
      satTextDim:  '#283848',
      snrUsedText: '#98b8d0',
      snrDimText:  '#283848',
    },
    night: {
      bg:          '#0e0000',
      ring:        '#280808',
      ring2:       '#180404',
      label:       '#582010',
      cardinal:    '#703020',
      snrBg:       '#0e0000',
      snrLabel:    '#401808',
      unusedAlpha: '44',
      override:    '#c83020',
      satText:     '#ffb090',
      satTextDim:  '#582010',
      snrUsedText: '#ff9878',
      snrDimText:  '#401808',
    },
    dayplus: {
      bg:          '#dce8f6',
      ring:        '#7aa4c8',
      ring2:       '#c4d8ec',
      label:       '#3060a0',
      cardinal:    '#003888',
      snrBg:       '#dce8f6',
      snrLabel:    '#2060a0',
      unusedAlpha: '70',
      satText:     '#00204a',
      satTextDim:  '#406090',
      snrUsedText: '#001030',
      snrDimText:  '#406090',
    },
  };

  function _theme() {
    const m = document.documentElement.getAttribute('data-mode') || 'day';
    return THEMES[m] || THEMES.day;
  }

  /* ── HiDPI setup ──────────────────────────────────────────────────────────
     Guarda dimensiones lógicas en dataset (primera vez) para evitar el
     feedback loop canvas.width → offsetWidth → canvas.width...           */
  function _setupCanvas(canvas) {
    const dpr = window.devicePixelRatio || 1;

    if (!canvas.dataset.logicalW) {
      const lw = canvas.offsetWidth  || parseInt(canvas.getAttribute('width'),  10) || 258;
      const lh = canvas.offsetHeight || parseInt(canvas.getAttribute('height'), 10) || 258;
      canvas.dataset.logicalW = lw;
      canvas.dataset.logicalH = lh;
      canvas.style.width  = lw + 'px';
      canvas.style.height = lh + 'px';
    }

    const W = parseInt(canvas.dataset.logicalW, 10);
    const H = parseInt(canvas.dataset.logicalH, 10);
    const wPx = Math.round(W * dpr);
    const hPx = Math.round(H * dpr);
    if (canvas.width !== wPx || canvas.height !== hPx) {
      canvas.width  = wPx;
      canvas.height = hPx;
    }

    const ctx = canvas.getContext('2d');
    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    return { ctx, W, H };
  }

  /* ── Overlay HTML labels ───────────────────────────────────────────────── */
  function _clearLabels(id) {
    const el = document.getElementById(id);
    if (el) el.innerHTML = '';
    return el;
  }

  /* Agrega un <span> al overlay en coordenadas lógicas del canvas.
     ox/oy = offset de alineación (ej. -0.5 para centrar horizontalmente).
     Las coords x,y son equivalentes a las de ctx.fillText en el canvas.  */
  function _addLabel(overlay, text, x, y, color, opts) {
    if (!overlay) return;
    const s = document.createElement('span');
    s.textContent = text;
    s.style.left  = Math.round(x) + 'px';
    s.style.top   = Math.round(y - 9) + 'px';   /* 9px ≈ ascent de 9px font */
    s.style.color = color;
    if (opts && opts.bold)     s.style.fontWeight = '700';
    if (opts && opts.size)     s.style.fontSize   = opts.size + 'px';
    if (opts && opts.centerX)  s.style.transform  = 'translateX(-50%)';
    overlay.appendChild(s);
  }

  /* ── Sky plot ─────────────────────────────────────────────────────────── */
  function drawSky(sats) {
    const canvas = document.getElementById('sky-canvas');
    if (!canvas) return;
    const t = _theme();
    const { ctx, W, H } = _setupCanvas(canvas);
    const cx = W / 2, cy = H / 2;
    const R  = Math.min(cx, cy) - 12;

    ctx.clearRect(0, 0, W, H);

    /* Fondo circular */
    const bgGrad = ctx.createRadialGradient(cx, cy, R * 0.05, cx, cy, R + 10);
    bgGrad.addColorStop(0, t.ring2 || t.bg);
    bgGrad.addColorStop(1, t.bg);
    ctx.beginPath(); ctx.arc(cx, cy, R + 10, 0, Math.PI * 2);
    ctx.fillStyle = bgGrad; ctx.fill();

    /* Anillos de elevación — solo formas, sin texto */
    [0, 30, 60].forEach(el => {
      const r = R * (1 - el / 90);
      ctx.beginPath(); ctx.arc(cx, cy, r, 0, Math.PI * 2);
      ctx.strokeStyle = t.ring;
      ctx.lineWidth   = el === 0 ? 1.2 : 0.7;
      ctx.setLineDash(el === 0 ? [] : [3, 4]);
      ctx.stroke();
      ctx.setLineDash([]);
    });

    /* Líneas cardinales */
    ctx.strokeStyle = t.ring; ctx.lineWidth = 0.7;
    ctx.setLineDash([4, 5]);
    ctx.beginPath(); ctx.moveTo(cx, cy - R); ctx.lineTo(cx, cy + R); ctx.stroke();
    ctx.beginPath(); ctx.moveTo(cx - R, cy); ctx.lineTo(cx + R, cy); ctx.stroke();
    ctx.setLineDash([]);

    /* Satélites — solo puntos y halos */
    (sats || []).forEach(s => {
      if (s.el == null || s.az == null) return;
      const r   = R * (1 - s.el / 90);
      const ang = (s.az - 90) * Math.PI / 180;
      const x   = cx + r * Math.cos(ang);
      const y   = cy + r * Math.sin(ang);

      const baseCol = t.override || SYS_COLOR[s.system] || '#94a3b8';
      const dotCol  = s.used ? baseCol : baseCol + t.unusedAlpha;
      const rad     = s.used ? 8 : 5;

      if (s.used) {
        ctx.beginPath(); ctx.arc(x, y, rad + 5, 0, Math.PI * 2);
        ctx.fillStyle = baseCol + '22'; ctx.fill();
      }

      ctx.beginPath(); ctx.arc(x, y, rad, 0, Math.PI * 2);
      ctx.fillStyle = dotCol; ctx.fill();

      if (s.used) {
        ctx.strokeStyle = 'rgba(255,255,255,0.80)';
        ctx.lineWidth = 1.5; ctx.stroke();
      } else {
        ctx.strokeStyle = baseCol + '55';
        ctx.lineWidth = 0.7; ctx.stroke();
      }
    });

    /* ── Labels HTML (nítidos) ─────────────────────────────────────────── */
    const ov = _clearLabels('sky-labels');

    /* Cardinales */
    _addLabel(ov, 'N', cx,          cy - R - 3,  t.cardinal, { bold: true, size: 11, centerX: true });
    _addLabel(ov, 'S', cx,          cy + R + 13, t.cardinal, { bold: true, size: 11, centerX: true });
    _addLabel(ov, 'E', cx + R + 4,  cy + 4,      t.cardinal, { bold: true, size: 11 });
    _addLabel(ov, 'W', cx - R - 13, cy + 4,      t.cardinal, { bold: true, size: 11 });

    /* Etiquetas de elevación (30° y 60°) */
    [30, 60].forEach(el => {
      const r = R * (1 - el / 90);
      _addLabel(ov, el + '°', cx + r + 3, cy - 1, t.label, { size: 8 });
    });

    /* PRN de satélites */
    (sats || []).forEach(s => {
      if (s.el == null || s.az == null) return;
      const r   = R * (1 - s.el / 90);
      const ang = (s.az - 90) * Math.PI / 180;
      const x   = cx + r * Math.cos(ang);
      const y   = cy + r * Math.sin(ang);
      const rad = s.used ? 8 : 5;
      const col = s.used ? t.satText : t.satTextDim;
      _addLabel(ov, s.prn, x + rad + 2, y + 4, col, { size: 8 });
    });

    /* Leyenda de sistemas */
    let lx = 6, ly = H - 4;
    Object.entries(SYS_COLOR).forEach(([sys, col]) => {
      const c = t.override || col;
      /* Cuadrito de color en canvas (sin texto) */
      ctx.fillStyle = c;
      ctx.fillRect(lx, ly - 7, 7, 7);
      /* Letra del sistema en overlay */
      _addLabel(ov, sys[0], lx + 9, ly, t.label, { size: 8 });
      lx += 22;
    });
  }

  /* ── SNR bars ─────────────────────────────────────────────────────────── */
  function drawSNR(sats) {
    const canvas = document.getElementById('snr-canvas');
    if (!canvas) return;
    const t = _theme();
    const { ctx, W, H } = _setupCanvas(canvas);

    ctx.clearRect(0, 0, W, H);
    ctx.fillStyle = t.snrBg; ctx.fillRect(0, 0, W, H);

    const visible = (sats || []).filter(s => s.snr != null).slice(0, 24);
    if (!visible.length) { _clearLabels('snr-labels'); return; }

    const barW = Math.floor((W - 4) / visible.length) - 1;
    const maxH  = H - 18;

    const ov = _clearLabels('snr-labels');

    visible.forEach((s, i) => {
      const snr  = s.snr || 0;
      const bh   = Math.round((snr / 50) * maxH);
      const x    = 2 + i * (barW + 1);
      const y    = H - 16 - bh;
      const baseCol = t.override || SYS_COLOR[s.system] || '#94a3b8';

      if (bh > 0) {
        const grad = ctx.createLinearGradient(x, y, x, y + bh);
        grad.addColorStop(0, baseCol);
        grad.addColorStop(1, baseCol + (s.used ? '80' : '28'));
        ctx.fillStyle = s.used ? grad : baseCol + '38';
        ctx.fillRect(x, y, barW, bh);

        if (s.used) {
          ctx.fillStyle = baseCol;
          ctx.fillRect(x, y, barW, 2);
        }
      }

      /* Labels HTML */
      if (snr > 0) {
        const snrCol = s.used ? (t.snrUsedText || baseCol) : t.snrDimText;
        _addLabel(ov, snr, x + barW / 2, y - 1, snrCol, { size: 7, centerX: true });
      }

      /* PRN debajo */
      const prnCol = s.used ? t.snrUsedText : t.snrDimText;
      _addLabel(ov, s.prn, x + barW / 2, H - 1, prnCol, { size: 7, centerX: true });
    });
  }

  /* ── API pública ──────────────────────────────────────────────────────── */
  let _lastSats = [];

  function update(sats) {
    _lastSats = sats || [];
    drawSky(_lastSats);
    drawSNR(_lastSats);

    const used = _lastSats.filter(s => s.used).length;
    const view = _lastSats.length;
    const u = document.getElementById('sat-used');
    const v = document.getElementById('sat-view');
    if (u) u.textContent = used;
    if (v) v.textContent = view;
  }

  function redraw() { drawSky(_lastSats); drawSNR(_lastSats); }

  return { update, redraw };
})();
