import { useRef } from 'react';
import { useFrame, useThree } from '@react-three/fiber';
import * as THREE from 'three';
import { useModelStore } from '@/stores/useModelStore';

const TRIG_ON = 0.7;
const TRIG_OFF = 0.3;
const MAX_RAY = 10; // meters

/**
 * Right-controller trigger driven measurement for AR.
 *
 * When `measureMode` is on and the user pulls the right trigger, casts a ray
 * forward from the controller (target-ray space). The first mesh hit becomes
 * a measurement point. Two pulls = one measurement (handled by the store).
 *
 * Uses hysteresis so a single trigger pull adds exactly one point.
 */
export function XRControllerMeasure() {
  const { scene, gl } = useThree();
  const triggered = useRef(false);
  const raycaster = useRef(new THREE.Raycaster());
  const tmpOrigin = useRef(new THREE.Vector3());
  const tmpDir = useRef(new THREE.Vector3());
  const tmpQuat = useRef(new THREE.Quaternion());

  useFrame((_state, _dt, frame: XRFrame | undefined) => {
    const measureMode = useModelStore.getState().measureMode;
    if (!measureMode || !frame) return;
    const session = frame.session;
    const refSpace = gl.xr.getReferenceSpace();
    if (!session || !refSpace) return;

    // Find right controller
    let right: XRInputSource | null = null;
    for (const src of session.inputSources) {
      if (src.handedness === 'right') { right = src; break; }
    }
    if (!right) return;

    const gp = right.gamepad;
    const trigBtn = gp?.buttons?.[0];
    const trigVal = trigBtn ? (trigBtn.value || (trigBtn.pressed ? 1 : 0)) : 0;

    // Rising edge with hysteresis
    if (!triggered.current && trigVal > TRIG_ON) {
      triggered.current = true;

      const raySpace = right.targetRaySpace ?? right.gripSpace;
      if (!raySpace) return;
      const pose = frame.getPose(raySpace, refSpace);
      if (!pose) return;

      const m = new THREE.Matrix4().fromArray(pose.transform.matrix);
      tmpOrigin.current.setFromMatrixPosition(m);
      tmpQuat.current.setFromRotationMatrix(m);
      // Controller aims along -Z in WebXR target-ray convention
      tmpDir.current.set(0, 0, -1).applyQuaternion(tmpQuat.current).normalize();

      raycaster.current.set(tmpOrigin.current, tmpDir.current);
      raycaster.current.far = MAX_RAY;

      const hits = raycaster.current.intersectObjects(scene.children, true);
      const hit = hits.find((h) => {
        const o = h.object;
        if (!(o instanceof THREE.Mesh)) return false;
        if (o.userData.__edgeLine) return false;
        if (o.geometry instanceof THREE.SphereGeometry) return false;
        if (o.geometry instanceof THREE.RingGeometry) return false;
        if (o.geometry instanceof THREE.PlaneGeometry) return false;
        return true;
      });
      if (hit) {
        useModelStore.getState().addMeasurePoint({
          x: hit.point.x, y: hit.point.y, z: hit.point.z,
        });
      }
    } else if (triggered.current && trigVal < TRIG_OFF) {
      triggered.current = false;
    }
  });

  return null;
}
