/**
 * interaction.js — Click/tap interaction in FPS navigation mode.
 *
 * - Raycasts against Timmy on pointerdown to apply slap.
 * - Short-tap detection (touchstart + touchend < 200ms) on right-half of
 *   mobile screen to also attempt slap / agent inspect.
 * - No OrbitControls — navigation is handled by navigation.js.
 */

import * as THREE from 'three';
import { AGENT_DEFS } from './agent-defs.js';
import { showInspectPopup } from './hud-labels.js';

let _canvas    = null;
let _camera    = null;
let _timmyGroup = null;
let _applySlap  = null;

const _raycaster = new THREE.Raycaster();
const _pointer   = new THREE.Vector2();
const _noCtxMenu = e => e.preventDefault();

// Agent inspect proxy — screen-space proximity check (80px threshold)
const INSPECT_RADIUS_PX = 80;

// Timmy world pos (for screen-space proximity check)
const _TIMMY_WORLD = new THREE.Vector3(0, 1.9, -2);
const _agentWorlds = AGENT_DEFS.map(d => ({ id: d.id, pos: new THREE.Vector3(d.x, 2.8, d.z) }));

// ── Public API ────────────────────────────────────────────────────────────────
export function registerSlapTarget(timmyGroup, applyFn) {
  _timmyGroup = timmyGroup;
  _applySlap  = applyFn;
}

export function initInteraction(camera, renderer) {
  _camera = camera;
  _canvas = renderer.domElement;

  _canvas.addEventListener('contextmenu', _noCtxMenu);
  _canvas.addEventListener('pointerdown', _onPointerDown, { capture: true });
}

export function updateControls() { /* no-op — navigation.js handles movement */ }

export function disposeInteraction() {
  if (_canvas) {
    _canvas.removeEventListener('contextmenu', _noCtxMenu);
    _canvas.removeEventListener('pointerdown', _onPointerDown, { capture: true });
    _canvas = null;
  }
  _camera     = null;
  _timmyGroup = null;
  _applySlap  = null;
}

// ── Internal ──────────────────────────────────────────────────────────────────
function _toScreen(worldPos) {
  const v = worldPos.clone().project(_camera);
  return {
    x: ( v.x *  0.5 + 0.5) * window.innerWidth,
    y: (-v.y *  0.5 + 0.5) * window.innerHeight,
    behind: v.z > 1,
  };
}

function _distPx(sx, sy, screenPos) {
  if (screenPos.behind) return Infinity;
  const dx = sx - screenPos.x;
  const dy = sy - screenPos.y;
  return Math.sqrt(dx * dx + dy * dy);
}

function _hitTestTimmy(clientX, clientY) {
  if (!_timmyGroup || !_applySlap || !_camera || !_canvas) return false;

  const rect = _canvas.getBoundingClientRect();
  _pointer.x = ((clientX - rect.left) / rect.width)  *  2 - 1;
  _pointer.y = ((clientY - rect.top)  / rect.height) * -2 + 1;

  _raycaster.setFromCamera(_pointer, _camera);
  const hits = _raycaster.intersectObject(_timmyGroup, true);

  if (hits.length > 0) {
    _applySlap(hits[0].point);
    return true;
  }

  // Fallback: screen-space proximity to Timmy (for mobile when mesh is small)
  const ts = _toScreen(_TIMMY_WORLD);
  if (_distPx(clientX, clientY, ts) < INSPECT_RADIUS_PX) {
    _applySlap(new THREE.Vector3(0, 1.2, -2));
    return true;
  }
  return false;
}

function _tryAgentInspect(clientX, clientY) {
  // Check Timmy first
  const ts = _toScreen(_TIMMY_WORLD);
  if (_distPx(clientX, clientY, ts) < INSPECT_RADIUS_PX) {
    showInspectPopup('timmy', clientX, clientY);
    return true;
  }
  // Sub-agents
  let best = null, bestDist = INSPECT_RADIUS_PX;
  for (const ag of _agentWorlds) {
    const s = _toScreen(ag.pos);
    const d = _distPx(clientX, clientY, s);
    if (d < bestDist) { best = ag; bestDist = d; }
  }
  if (best) {
    showInspectPopup(best.id, clientX, clientY);
    return true;
  }
  return false;
}

// Track touch for short-tap detection on mobile
let _tapStart = 0;
let _tapX = 0, _tapY = 0;

function _onPointerDown(event) {
  // Record tap start for short-tap detection
  _tapStart = Date.now();
  _tapX = event.clientX;
  _tapY = event.clientY;

  const isTouch = event.pointerType === 'touch';

  if (isTouch) {
    // For mobile: add a pointerup listener to detect short tap
    const onUp = (upEvent) => {
      _canvas.removeEventListener('pointerup', onUp);
      const dt    = Date.now() - _tapStart;
      const moved = Math.hypot(upEvent.clientX - _tapX, upEvent.clientY - _tapY);
      if (dt < 220 && moved < 18) {
        // Short tap — try slap then inspect
        if (!_hitTestTimmy(upEvent.clientX, upEvent.clientY)) {
          _tryAgentInspect(upEvent.clientX, upEvent.clientY);
        }
      }
    };
    _canvas.addEventListener('pointerup', onUp, { once: true });
  } else {
    // Desktop click: only fire when pointer lock is already active
    // (otherwise navigation.js requests lock on this same click — that's fine,
    //  both can fire; slap + lock request together is acceptable)
    if (document.pointerLockElement === _canvas) {
      // Cast from screen center in FPS mode
      _pointer.set(0, 0);
      _raycaster.setFromCamera(_pointer, _camera);
      if (_timmyGroup && _applySlap) {
        const hits = _raycaster.intersectObject(_timmyGroup, true);
        if (hits.length > 0) {
          _applySlap(hits[0].point);
          event.stopImmediatePropagation();
        }
      }
    }
  }
}
