import * as THREE from 'three';

/**
 * STABLE VIEWPORT CORE — shared store.
 * Singleton bridge between the WebGL scene (producers) and the DOM overlay
 * (consumer). Kept outside React so per-frame updates never trigger React
 * re-renders inside the Canvas. No Drei, no portals, no shaders.
 */

// Live viewport state, written each frame from inside the Canvas.
export const viewport = {
  camera: null,
  gl: null,
  width: 1,
  height: 1,
  ready: false,
  info: null,          // { calls, triangles, geometries, textures }
  error: null,         // last core/layer error message
  contextLost: false,  // WebGL context-loss flag
  controlsCount: 0,
};

// Labels are plain data (no React nodes) so the DOM overlay can render them.
const labels = new Map();

export function setViewport(patch) { Object.assign(viewport, patch); }
export function getViewport() { return viewport; }

export function registerLabel(id, label) { labels.set(id, label); }
export function unregisterLabel(id) { labels.delete(id); }
export function clearLabels() { labels.clear(); }
export function getLabels() { return Array.from(labels.values()); }

const _v = new THREE.Vector3();
// Project a world-space [x,y,z] to screen pixels relative to the viewport box.
// Returns null when the camera is unavailable or the point is behind it.
export function projectToScreen(worldPos) {
  if (!viewport.camera) return null;
  _v.set(worldPos[0], worldPos[1], worldPos[2]);
  _v.project(viewport.camera);
  if (_v.z > 1) return null;
  return {
    x: (_v.x * 0.5 + 0.5) * viewport.width,
    y: (-_v.y * 0.5 + 0.5) * viewport.height,
  };
}