import { useEffect, useRef } from 'react';
import { useFrame, useThree } from '@react-three/fiber';
import * as THREE from 'three';
import { setBroadcastSource } from '@/lib/webrtc/broadcastSource';

interface XRBroadcastMirrorProps {
  enabled: boolean;
  width?: number;
  height?: number;
  /** Solid background color used in place of real passthrough (privacy + clarity). */
  backgroundColor?: string;
}

/**
 * Renders the current scene to an OFFSCREEN opaque canvas every frame so a
 * MediaStream can capture it. The main XR canvas uses alpha:true for
 * passthrough — viewers receiving captureStream() of that would see only
 * the 3D content over transparency. This mirror gives them a usable picture.
 */
export function XRBroadcastMirror({
  enabled,
  width = 1280,
  height = 720,
  backgroundColor = '#1a1a1a',
}: XRBroadcastMirrorProps) {
  const { gl, scene } = useThree();
  const canvasRef = useRef<HTMLCanvasElement | null>(null);
  const rendererRef = useRef<THREE.WebGLRenderer | null>(null);
  const mirrorCamRef = useRef<THREE.PerspectiveCamera | null>(null);

  // Create / dispose the offscreen renderer
  useEffect(() => {
    if (!enabled) return;
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    canvasRef.current = canvas;

    const renderer = new THREE.WebGLRenderer({
      canvas,
      alpha: false,
      antialias: true,
      powerPreference: 'high-performance',
      preserveDrawingBuffer: false,
    });
    renderer.setPixelRatio(1);
    renderer.setSize(width, height, false);
    renderer.setClearColor(new THREE.Color(backgroundColor), 1);
    renderer.outputColorSpace = THREE.SRGBColorSpace;
    rendererRef.current = renderer;

    mirrorCamRef.current = new THREE.PerspectiveCamera(70, width / height, 0.01, 100);

    setBroadcastSource(canvas);

    return () => {
      setBroadcastSource(null);
      renderer.dispose();
      rendererRef.current = null;
      canvasRef.current = null;
      mirrorCamRef.current = null;
    };
  }, [enabled, width, height, backgroundColor]);

  // Per-frame mirror render (throttled to ~24 fps to save GPU)
  const lastTime = useRef(0);
  useFrame(() => {
    if (!enabled) return;
    const renderer = rendererRef.current;
    const mirrorCam = mirrorCamRef.current;
    if (!renderer || !mirrorCam) return;

    const now = performance.now();
    if (now - lastTime.current < 42) return; // ~24 fps cap
    lastTime.current = now;

    // Pick the best available camera: XR camera if in session, else main camera
    let srcCam: THREE.Camera | null = null;
    const xrCam = (gl.xr as unknown as { isPresenting?: boolean; getCamera?: () => THREE.ArrayCamera }).getCamera?.();
    const isPresenting = (gl.xr as unknown as { isPresenting?: boolean }).isPresenting;
    if (isPresenting && xrCam && (xrCam as THREE.ArrayCamera).cameras?.length) {
      srcCam = (xrCam as THREE.ArrayCamera).cameras[0]; // left eye
    }

    if (srcCam instanceof THREE.PerspectiveCamera) {
      mirrorCam.fov = srcCam.fov;
      mirrorCam.near = srcCam.near;
      mirrorCam.far = srcCam.far;
    }
    if (srcCam) {
      srcCam.updateMatrixWorld(true);
      mirrorCam.position.setFromMatrixPosition(srcCam.matrixWorld);
      mirrorCam.quaternion.setFromRotationMatrix(srcCam.matrixWorld);
    } else {
      // Fallback: use the main R3F camera (desktop preview)
      const main = (gl as unknown as { __mainCam?: THREE.Camera }).__mainCam;
      if (main) {
        main.updateMatrixWorld(true);
        mirrorCam.position.setFromMatrixPosition(main.matrixWorld);
        mirrorCam.quaternion.setFromRotationMatrix(main.matrixWorld);
        if (main instanceof THREE.PerspectiveCamera) {
          mirrorCam.fov = main.fov;
          mirrorCam.near = main.near;
          mirrorCam.far = main.far;
        }
      }
    }
    mirrorCam.aspect = width / height;
    mirrorCam.updateProjectionMatrix();

    try {
      renderer.render(scene, mirrorCam);
    } catch (e) {
      console.warn('[XRBroadcastMirror] render failed', e);
    }
  });

  return null;
}
