// Shared helpers used across layers. Cesium and satellite are CDN globals.

const Cesium = window.Cesium;

// Build an offscreen canvas glyph for a BillboardCollection.
export function makeGlyphCanvas(size, drawFn) {
  const c = document.createElement('canvas');
  c.width = size;
  c.height = size;
  drawFn(c.getContext('2d'), size);
  return c;
}

// White upward-pointing triangle (aircraft). Tinted per-billboard via .color.
export function aircraftGlyph() {
  return makeGlyphCanvas(32, (g) => {
    g.fillStyle = '#ffffff';
    g.beginPath();
    g.moveTo(16, 2);
    g.lineTo(28, 30);
    g.lineTo(16, 23);
    g.lineTo(4, 30);
    g.closePath();
    g.fill();
  });
}

// Upward teardrop/flame (wildfires). Drawn directly in `hex` with a dark
// outline — one shared canvas reused across every fire billboard.
export function flameGlyph(hex) {
  return makeGlyphCanvas(28, (g, s) => {
    const cx = s / 2;
    g.beginPath();
    g.moveTo(cx, 3); // pointed top
    g.bezierCurveTo(s * 0.86, s * 0.34, s * 0.80, s * 0.72, cx, s - 4);
    g.bezierCurveTo(s * 0.20, s * 0.72, s * 0.14, s * 0.34, cx, 3);
    g.closePath();
    g.fillStyle = hex;
    g.fill();
    g.lineWidth = 2;
    g.strokeStyle = '#0a0f14';
    g.stroke();
  });
}

// White diamond (ships).
export function shipGlyph() {
  return makeGlyphCanvas(28, (g) => {
    g.fillStyle = '#ffffff';
    g.beginPath();
    g.moveTo(14, 2);
    g.lineTo(26, 14);
    g.lineTo(14, 26);
    g.lineTo(2, 14);
    g.closePath();
    g.fill();
  });
}

// Great-circle initial bearing, degrees (0 = north, clockwise).
export function bearingDeg(lat1, lon1, lat2, lon2) {
  const toR = Math.PI / 180;
  const p1 = lat1 * toR;
  const p2 = lat2 * toR;
  const dl = (lon2 - lon1) * toR;
  const y = Math.sin(dl) * Math.cos(p2);
  const x = Math.cos(p1) * Math.sin(p2) - Math.sin(p1) * Math.cos(p2) * Math.cos(dl);
  return (Math.atan2(y, x) * 180 / Math.PI + 360) % 360;
}

// Aircraft altitude → band color.
export function altitudeColor(CONFIG, altMeters) {
  const c = CONFIG.colors;
  if (altMeters == null) return c.aircraftHigh;
  if (altMeters < 3000) return c.aircraftLow;
  if (altMeters < 9000) return c.aircraftMid;
  return c.aircraftHigh;
}

// Escape a string for safe interpolation into InfoBox description HTML.
// Feeds like USGS/EONET are trusted, but this is defense-in-depth for the
// public deploy (and the InfoBox is a real HTML sink).
export function escapeHtml(s) {
  return String(s == null ? '' : s)
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;');
}

// Only allow http(s) URLs into href attributes (blocks javascript:/data: URLs).
export function safeUrl(u) {
  const s = String(u == null ? '' : u).trim();
  return /^https?:\/\//i.test(s) ? s : '';
}

// CSS hex → Cesium.Color, optional alpha.
export function cz(hex, alpha) {
  const col = Cesium.Color.fromCssColorString(hex);
  return alpha == null ? col : col.withAlpha(alpha);
}

// Billboard screen-space rotation (CCW) for a compass heading (CW from north).
export function headingToRotation(headingDeg) {
  return -Cesium.Math.toRadians(headingDeg || 0);
}
