/**
 * hud-labels.js — AR floating HTML labels projected from 3D world positions.
 *
 * Each label is a <div> element that gets repositioned every frame by projecting
 * the agent's 3D world position through the camera to screen space.
 *
 * Exports:
 *   initHudLabels(scene, camera, agentDefs, getTimmyPosition)
 *   updateHudLabels(camera, renderer, agentStates)
 *   setLabelState(id, state)     — called from websocket.js on agent_state events
 *   disposeHudLabels()
 */

import * as THREE from 'three';
import { colorToCss } from './agent-defs.js';

const _proj   = new THREE.Vector3();
let   _camera = null;
let   _labels = [];    // { el, worldPos: THREE.Vector3, id }

// ── State cache (updated from WS) ────────────────────────────────────────────
const _states = {};

// ── Inspect popup ─────────────────────────────────────────────────────────────
let _inspectEl    = null;
let _inspectTimer = null;

export function initHudLabels(camera, agentDefs, timmyWorldPos) {
  _camera = camera;

  const container = document.getElementById('ar-labels') || (() => {
    const c = document.createElement('div');
    c.id = 'ar-labels';
    c.style.cssText = 'position:fixed;inset:0;pointer-events:none;z-index:15;overflow:hidden;';
    document.body.appendChild(c);
    return c;
  })();

  // Timmy label
  _labels.push(_makeLabel(container, 'timmy', 'TIMMY', 'Wizard · Master Agent', '#c77dff',
    timmyWorldPos.clone().add(new THREE.Vector3(0, 1.1, 0))));

  // Sub-agent labels
  for (const def of agentDefs) {
    const col = colorToCss(def.color);
    const pos = new THREE.Vector3(def.x, 2.8, def.z);
    _labels.push(_makeLabel(container, def.id, def.label, def.role, col, pos));
    _states[def.id] = 'idle';
  }

  _states['timmy'] = 'idle';

  // Inspect popup (shared, shown on tap)
  _inspectEl = document.createElement('div');
  _inspectEl.id = 'inspect-popup';
  _inspectEl.style.cssText = [
    'position:fixed;transform:translate(-50%,-100%) translateY(-14px)',
    'background:rgba(8,6,20,0.92);border:1px solid rgba(120,80,200,0.6)',
    'border-radius:10px;padding:10px 16px;min-width:140px;max-width:220px',
    'color:#ddd;font-family:Courier New,monospace;font-size:11px;line-height:1.7',
    'pointer-events:none;z-index:30;display:none',
    'box-shadow:0 0 24px rgba(100,60,180,0.4)',
    'backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)',
  ].join(';');
  document.body.appendChild(_inspectEl);
}

function _makeLabel(container, id, name, role, color, worldPos) {
  const el = document.createElement('div');
  el.className = 'ar-label';
  el.dataset.id = id;
  el.style.cssText = [
    'position:absolute;transform:translate(-50%,-100%)',
    'pointer-events:none;transition:opacity 0.3s',
    'text-align:center;line-height:1.4',
  ].join(';');

  el.innerHTML = `
    <div class="ar-label-name" style="color:${color};font-family:Courier New,monospace;
      font-size:11px;font-weight:bold;letter-spacing:2px;
      text-shadow:0 0 10px ${color}88;white-space:nowrap;">
      ${name}
    </div>
    <div class="ar-label-role" style="color:${color}99;font-family:Courier New,monospace;
      font-size:9px;letter-spacing:1px;text-transform:uppercase;white-space:nowrap;">
      ${role}
    </div>
    <div class="ar-label-state" style="margin-top:2px;">
      <span class="ar-dot" style="display:inline-block;width:6px;height:6px;
        border-radius:50%;background:${color};opacity:0.7;
        box-shadow:0 0 6px ${color};margin-right:4px;vertical-align:middle;"></span>
      <span class="ar-state-text" style="color:${color}bb;font-family:Courier New,monospace;
        font-size:9px;letter-spacing:1px;">idle</span>
    </div>
    <div class="ar-label-tick" style="width:1px;height:14px;background:${color}55;
      margin:3px auto 0;"></div>
  `;

  container.appendChild(el);
  return { el, worldPos, id, color };
}

export function setLabelState(id, state) {
  _states[id] = state;
  const entry = _labels.find(l => l.id === id);
  if (!entry) return;
  const stateEl = entry.el.querySelector('.ar-state-text');
  const dot     = entry.el.querySelector('.ar-dot');
  if (stateEl) stateEl.textContent = state;
  const pulse = state !== 'idle';
  if (dot) dot.style.animation = pulse ? 'ar-pulse 1s ease-in-out infinite' : '';
}

export function showInspectPopup(id, screenX, screenY) {
  if (!_inspectEl) return;
  const entry = _labels.find(l => l.id === id);
  if (!entry) return;

  const state  = _states[id] || 'idle';
  const uptime = Math.floor(performance.now() / 1000);
  _inspectEl.innerHTML = `
    <div style="color:${entry.color};font-weight:bold;letter-spacing:2px;font-size:12px;margin-bottom:6px;">
      ${id.toUpperCase()}
    </div>
    <div style="color:#aaa;margin-bottom:2px;">state&nbsp;&nbsp;: <span style="color:${entry.color}">${state}</span></div>
    <div style="color:#aaa;margin-bottom:2px;">uptime : ${uptime}s</div>
    <div style="color:#aaa;">network: <span style="color:#44ff88">connected</span></div>
  `;
  _inspectEl.style.left    = `${screenX}px`;
  _inspectEl.style.top     = `${screenY}px`;
  _inspectEl.style.display = 'block';

  if (_inspectTimer) clearTimeout(_inspectTimer);
  _inspectTimer = setTimeout(() => {
    if (_inspectEl) _inspectEl.style.display = 'none';
  }, 2800);
}

const _ndc = new THREE.Vector3();

export function updateHudLabels(camera, renderer) {
  if (!camera) return;

  const W = renderer.domElement.clientWidth  || window.innerWidth;
  const H = renderer.domElement.clientHeight || window.innerHeight;

  for (const label of _labels) {
    _ndc.copy(label.worldPos);
    _ndc.project(camera);

    // Behind camera or outside NDC → hide
    if (_ndc.z > 1 || Math.abs(_ndc.x) > 1.8 || Math.abs(_ndc.y) > 1.8) {
      label.el.style.opacity = '0';
      continue;
    }

    const sx = (_ndc.x *  0.5 + 0.5) * W;
    const sy = (_ndc.y * -0.5 + 0.5) * H;

    label.el.style.left    = `${sx}px`;
    label.el.style.top     = `${sy}px`;

    // Fade with distance: full opacity 3–20 units, fade out beyond 20
    const dist  = _proj.copy(label.worldPos).distanceTo(camera.position);
    const alpha = Math.max(0, Math.min(1, 1 - (dist - 20) / 10));
    label.el.style.opacity = alpha.toFixed(2);
  }
}

export function disposeHudLabels() {
  for (const l of _labels) l.el.remove();
  _labels = [];
  _inspectEl?.remove();
  _inspectEl = null;
}
