// Interactions for the 3D Three.js scene.
// Hover/click are driven by raycasting via window.__scene.raycastAtClient().
// Tooltip + pinned panel UX is identical to the previous SVG version.

(function () {
  function init() {
    const canvas = document.getElementById('three-canvas');
    if (!canvas) return;
    if (canvas.__bound) return;
    canvas.__bound = true;

    const tooltip = document.getElementById('tooltip');
    const reticle = document.getElementById('reticle');
    const clickHint = document.getElementById('clickHint');
    const panel = document.getElementById('panel');
    const scrim = document.getElementById('scrim');
    const panelNum = document.getElementById('panelNum');
    const panelEyebrow = document.getElementById('panelEyebrow');
    const panelTitle = document.getElementById('panelTitle');
    const panelSub = document.getElementById('panelSub');
    const panelBody = document.getElementById('panelBody');
    const panelClose = document.getElementById('panelClose');

    let pinnedId = null;
    let hoverId = null;
    let mode = 'explode';

    // Mobile = coarse pointer or narrow viewport. We use this to:
    //   • skip the hover/tooltip/reticle code path (touch screens have no hover state)
    //   • skip the onboarding click-hint banner (which targets the hidden legend pill)
    //   • enable swipe-down dismiss on the bottom-sheet panel
    const IS_MOBILE = (window.matchMedia && window.matchMedia('(max-width: 740px)').matches) ||
                      (window.matchMedia && window.matchMedia('(pointer: coarse)').matches);

    window.__setMode = (m) => {
      mode = m;
      if (window.__scene) window.__scene.setMode(m);
    };
    window.__setMode('explode');

    function setHover(id) {
      hoverId = id;
      if (window.__scene) window.__scene.setHover(id);
    }

    function showTooltip(id, x, y) {
      const data = window.SUBSYSTEMS[id];
      if (!data) return;
      tooltip.innerHTML = `
        <div class="tt-content">
          <div class="tt-num">${data.num} · ${data.eyebrow}</div>
          <div class="tt-title">${data.title}</div>
          <div class="tt-sub">${data.sub}</div>
          <div class="tt-desc">${data.short}</div>
        </div>
        <div class="tt-hint">
          <span>CLICK TO INSPECT</span>
          <span class="arrow">▸</span>
        </div>
      `;
      tooltip.classList.add('show');
      positionTooltip(x, y);
    }
    function positionTooltip(x, y) {
      const pad = 16;
      const w = tooltip.offsetWidth, h = tooltip.offsetHeight;
      let nx = x + pad, ny = y + pad;
      if (nx + w + 8 > window.innerWidth)  nx = x - w - pad;
      if (ny + h + 8 > window.innerHeight) ny = y - h - pad;
      tooltip.style.left = Math.max(8, nx) + 'px';
      tooltip.style.top  = Math.max(8, ny) + 'px';
    }
    function hideTooltip() { tooltip.classList.remove('show'); }

    // Reticle (cursor follower) — only when hovering a hittable part
    function showReticle(x, y) {
      if (!reticle) return;
      reticle.style.left = x + 'px';
      reticle.style.top  = y + 'px';
      reticle.classList.add('show');
      canvas.classList.add('is-over-hot');
    }
    function hideReticle() {
      if (!reticle) return;
      reticle.classList.remove('show');
      canvas.classList.remove('is-over-hot');
    }
    function moveReticle(x, y) {
      if (!reticle) return;
      reticle.style.left = x + 'px';
      reticle.style.top  = y + 'px';
    }

    // First-touch state — used to glow the legend & show the click hint
    document.body.classList.add('untouched');
    let touched = false;
    function markTouched() {
      if (touched) return;
      touched = true;
      document.body.classList.remove('untouched');
      if (clickHint) clickHint.classList.remove('show');
    }

    // Show the onboarding hint shortly after scene load, hide on first hover
    function showOnboarding() {
      if (!clickHint || touched || IS_MOBILE) return;
      console.log('[onboarding] showing click hint');
      clickHint.classList.add('show');
      // Auto-hide after a while even if user never hovers
      setTimeout(() => { clickHint.classList.remove('show'); }, 8000);
    }
    // Wait for the scene to be ready before nudging the user
    (function waitReady() {
      if (window.__SCENE_READY) {
        setTimeout(showOnboarding, 600);
      } else {
        setTimeout(waitReady, 200);
      }
    })();
    // Belt-and-braces: also fire after a fixed delay regardless of scene-ready,
    // so the hint definitely appears even if the readiness flag misses.
    setTimeout(showOnboarding, 1500);

    // Drag-to-rotate
    let dragging = false, dragX = 0, dragY = 0, dragMoved = 0;
    // Pinch state — declared up here so pointerdown can check it before we
    // assign in the touchstart handler below.
    let pinching = false;
    let pinchStartDist = 0;
    let pinchStartScale = 1;
    canvas.addEventListener('pointerdown', (e) => {
      // Pinch in progress? skip rotate gesture.
      if (pinching) return;
      dragging = true; dragX = e.clientX; dragY = e.clientY; dragMoved = 0;
      canvas.setPointerCapture(e.pointerId);
    });
    canvas.addEventListener('pointerup', (e) => {
      dragging = false;
      try { canvas.releasePointerCapture(e.pointerId); } catch {}
    });
    canvas.addEventListener('pointercancel', () => { dragging = false; });

    // ─── Pinch-to-resize (touch only) ───────────────────────────────
    // Two-finger pinch scales the device via window.__scene.setUserScale().
    // While pinching, drag/rotate is suppressed (pointerdown bails early).
    function touchDist(t) {
      const dx = t[0].clientX - t[1].clientX;
      const dy = t[0].clientY - t[1].clientY;
      return Math.hypot(dx, dy);
    }
    canvas.addEventListener('touchstart', (e) => {
      if (e.touches.length === 2 && window.__scene) {
        pinching = true;
        dragging = false;  // cancel any in-flight rotate
        pinchStartDist = touchDist(e.touches);
        pinchStartScale = window.__scene.getUserScale ? window.__scene.getUserScale() : 1;
        e.preventDefault();
      }
    }, { passive: false });
    canvas.addEventListener('touchmove', (e) => {
      if (pinching && e.touches.length === 2 && window.__scene) {
        const d = touchDist(e.touches);
        if (pinchStartDist > 0) {
          const ratio = d / pinchStartDist;
          window.__scene.setUserScale(pinchStartScale * ratio);
        }
        e.preventDefault();
      }
    }, { passive: false });
    function endPinch(e) {
      if (e && e.touches && e.touches.length < 2) pinching = false;
    }
    canvas.addEventListener('touchend', endPinch);
    canvas.addEventListener('touchcancel', endPinch);

    canvas.addEventListener('pointermove', (e) => {
      if (dragging) {
        const dx = e.clientX - dragX;
        const dy = e.clientY - dragY;
        dragX = e.clientX; dragY = e.clientY;
        dragMoved += Math.abs(dx) + Math.abs(dy);
        if (window.__scene) window.__scene.rotateBy(dx * 0.005, dy * 0.003);
        return;
      }
      // No hover preview on touch devices — they tap, the panel opens directly.
      if (IS_MOBILE) return;
      if (pinnedId) return;
      if (!window.__scene || !window.__SCENE_READY) return;
      const id = window.__scene.raycastAtClient(e.clientX, e.clientY);
      if (id !== hoverId) {
        if (id) {
          setHover(id);
          showTooltip(id, e.clientX, e.clientY);
          showReticle(e.clientX, e.clientY);
          markTouched();
        } else {
          setHover(null);
          hideTooltip();
          hideReticle();
        }
      } else if (id) {
        positionTooltip(e.clientX, e.clientY);
        moveReticle(e.clientX, e.clientY);
      }
    });

    canvas.addEventListener('pointerleave', () => {
      if (pinnedId) return;
      setHover(null);
      hideTooltip();
      hideReticle();
    });

    canvas.addEventListener('click', (e) => {
      // Suppress clicks that came from a drag
      if (dragMoved > 6) return;
      if (!window.__scene || !window.__SCENE_READY) return;
      const id = window.__scene.raycastAtClient(e.clientX, e.clientY);
      if (!id) return;
      markTouched();
      hideReticle();
      pin(id);
    });

    function buildPanelBody(data) {
      return data.sections.map((sec) => {
        let inner = '';
        if (sec.bullets) {
          inner = '<ul>' + sec.bullets.map((b) => `<li>${b}</li>`).join('') + '</ul>';
        } else if (sec.skills) {
          inner = sec.skills.map(([name, pct]) => `
            <div class="skill-row">
              <span class="skill-name">${name}</span>
              <div class="skill-bar-wrap"><div class="skill-bar" data-pct="${pct}"></div></div>
              <span class="skill-pct">${pct}</span>
            </div>
          `).join('');
        } else if (sec.tags) {
          inner = '<div class="tags">' + sec.tags.map((t) => `<span class="tag">${t}</span>`).join('') + '</div>';
        }
        return `
          <div class="panel-section">
            <div class="panel-section-title">${sec.title}</div>
            ${inner}
          </div>
        `;
      }).join('');
    }

    function pin(id) {
      const data = window.SUBSYSTEMS[id];
      if (!data) return;
      pinnedId = id;
      if (window.__scene) window.__scene.setPinned(id);
      hideTooltip();
      document.body.classList.add('pinned');

      panelNum.textContent = data.num;
      panelEyebrow.textContent = data.eyebrow;
      panelTitle.textContent = data.title;
      panelSub.textContent = data.sub;
      panelBody.innerHTML = buildPanelBody(data);

      panel.classList.add('open');
      panel.setAttribute('aria-hidden', 'false');
      scrim.classList.add('open');

      requestAnimationFrame(() => {
        panel.querySelectorAll('.skill-bar').forEach((b, i) => {
          const pct = b.getAttribute('data-pct');
          setTimeout(() => { b.style.width = pct + '%'; }, 80 + i * 50);
        });
      });

      setHover(id);
    }
    function unpin() {
      pinnedId = null;
      if (window.__scene) window.__scene.setPinned(null);
      document.body.classList.remove('pinned');
      panel.classList.remove('open');
      panel.setAttribute('aria-hidden', 'true');
      scrim.classList.remove('open');
      setHover(null);
    }
    panelClose.addEventListener('click', unpin);
    scrim.addEventListener('click', unpin);

    // Bottom-sheet swipe-down dismiss (mobile only).
    // Listens at the panel root — a vertical drag with > 80px or > 35% of sheet height
    // closes the sheet. Otherwise the sheet snaps back via CSS transition.
    if (IS_MOBILE) {
      let sheetStartY = 0, sheetCurY = 0, sheetDragging = false;
      panel.addEventListener('touchstart', (e) => {
        // Only start a sheet-drag from the top region (handle / header) so the inner
        // content can scroll freely.
        const rect = panel.getBoundingClientRect();
        const localY = e.touches[0].clientY - rect.top;
        if (localY > 70) return; // drag from handle/header zone only
        sheetDragging = true;
        sheetStartY = e.touches[0].clientY;
        sheetCurY = sheetStartY;
        panel.style.transition = 'none';
      }, { passive: true });
      panel.addEventListener('touchmove', (e) => {
        if (!sheetDragging) return;
        sheetCurY = e.touches[0].clientY;
        const dy = Math.max(0, sheetCurY - sheetStartY);
        panel.style.transform = `translateY(${dy}px)`;
      }, { passive: true });
      panel.addEventListener('touchend', () => {
        if (!sheetDragging) return;
        sheetDragging = false;
        panel.style.transition = '';
        const dy = Math.max(0, sheetCurY - sheetStartY);
        const threshold = Math.min(120, panel.offsetHeight * 0.30);
        if (dy > threshold) {
          panel.style.transform = '';
          unpin();
        } else {
          panel.style.transform = '';
        }
      });
    }

    document.querySelectorAll('[data-action="reset"]').forEach((el) => {
      el.addEventListener('click', (e) => { e.preventDefault(); unpin(); });
    });

    window.addEventListener('keydown', (e) => {
      if (e.key === 'Escape') unpin();
      if (e.key.toLowerCase() === 'm') {
        const order = ['explode', 'xray', 'cross'];
        const next = order[(order.indexOf(mode) + 1) % order.length];
        window.__setMode(next);
        window.dispatchEvent(new CustomEvent('mode-changed', { detail: next }));
      }
    });
  }

  init();
  setTimeout(init, 200);
  setTimeout(init, 800);
})();
