import { jsxs, jsx } from "react/jsx-runtime";
import { useRef, useEffect, useState } from "react";
import { useThree, useFrame } from "@react-three/fiber";
import { Bvh } from "@react-three/drei";
import { useXR, useXRInputSourceState } from "@react-three/xr";
import { Matrix4, Vector3, Box3, FrontSide } from "three";
import { i as isValidGeometrySize, M as MeasureLine, s as stringifyLineData } from "./index-6Oxzw9ho.js";
function getHandJoint(hand, jointName) {
  return hand.get(jointName);
}
function getJointPosition(hand, jointName, frame, refSpace) {
  if (!hand?.inputSource?.hand)
    return null;
  const jointSpace = getHandJoint(hand.inputSource.hand, jointName);
  if (!jointSpace)
    return null;
  const pose = frame.getJointPose?.(jointSpace, refSpace);
  if (!pose)
    return null;
  return new Vector3(pose.transform.position.x, pose.transform.position.y, pose.transform.position.z);
}
function isPinching(hand, frame, refSpace, threshold = 0.02) {
  const thumbPos = getJointPosition(hand, "thumb-tip", frame, refSpace);
  const indexPos = getJointPosition(hand, "index-finger-tip", frame, refSpace);
  if (!thumbPos || !indexPos)
    return false;
  return thumbPos.distanceTo(indexPos) < threshold;
}
function GeometryAndMeshXR(props) {
  const { segmentationGroup, segmentationSettings, segmentationSceneScale, renderingSettings, materialRef, highlightEntity, setObsHighlight } = props;
  const model = useRef(null);
  const distanceRef = useRef(null);
  const rayGrabGroup = useRef(null);
  const grabControllerRef = useRef(null);
  useRef(new Matrix4());
  const initialScale = useRef(null);
  const secondPointerId = useRef(null);
  const initialDistance = useRef(0);
  const lastPointerPositions = useRef(/* @__PURE__ */ new Map());
  const session = useXR((state) => state.session);
  const isPresenting = session != null;
  useEffect(() => {
    if (materialRef?.current?.material?.uniforms?.u_physical_Pixel) {
      materialRef.current.material.uniforms.u_physical_Pixel.value = isPresenting ? 0.2 : 2.5;
    }
  }, [isPresenting, materialRef]);
  const { scene, gl } = useThree();
  const rightHand = useXRInputSourceState("hand", "right");
  const leftHand = useXRInputSourceState("hand", "left");
  const [measureState, setMeasureState] = useState(false);
  const [highlighted, setHighlighted] = useState(false);
  const [showLine, setShowLine] = useState(false);
  const [currentLine, setCurrentLine] = useState({
    startPoint: new Vector3(),
    midPoint: new Vector3(),
    endPoint: new Vector3(),
    setStartPoint: false,
    setEndPoint: false
  });
  const [lines, setLines] = useState([]);
  const [debounce, setDebounce] = useState(0);
  const measureStateRef = useRef(measureState);
  measureStateRef.current = measureState;
  const highlightedRef = useRef(highlighted);
  highlightedRef.current = highlighted;
  const currentLineRef = useRef(currentLine);
  currentLineRef.current = currentLine;
  const linesRef = useRef(lines);
  linesRef.current = lines;
  const debounceRef = useRef(debounce);
  debounceRef.current = debounce;
  useFrame((_state, _delta, frame) => {
    if (!isPresenting || !frame)
      return;
    const refSpace = gl.xr.getReferenceSpace();
    if (!refSpace)
      return;
    const rightTipBbox = scene.getObjectByName("rightTipBbox");
    const leftTipBbox = scene.getObjectByName("leftTipBbox");
    if (!rightTipBbox || !leftTipBbox)
      return;
    const leftTipBB = new Box3().setFromObject(leftTipBbox);
    const rightTipBB = new Box3().setFromObject(rightTipBbox);
    let intersected = false;
    setDebounce((prev) => prev - 1);
    if (leftTipBB.intersectsBox(rightTipBB) && leftTipBB.max.x !== -rightTipBB.min.x) {
      setMeasureState(true);
      setShowLine(true);
      setCurrentLine({
        startPoint: new Vector3(),
        midPoint: new Vector3(),
        endPoint: new Vector3(),
        setStartPoint: false,
        setEndPoint: false
      });
    }
    const curMeasureState = measureStateRef.current;
    const curLine = currentLineRef.current;
    if (curMeasureState) {
      let leftFingerPosition = getJointPosition(leftHand, "index-finger-tip", frame, refSpace);
      let rightFingerPosition = getJointPosition(rightHand, "index-finger-tip", frame, refSpace);
      if (!leftFingerPosition || !rightFingerPosition)
        return;
      if (rayGrabGroup.current) {
        leftFingerPosition = leftFingerPosition.applyMatrix4(rayGrabGroup.current.matrixWorld.clone().invert());
        rightFingerPosition = rightFingerPosition.applyMatrix4(rayGrabGroup.current.matrixWorld.clone().invert());
      }
      let currentStart = leftFingerPosition.clone();
      let currentEnd = rightFingerPosition.clone();
      if (curLine.setStartPoint) {
        currentStart = curLine.startPoint;
      }
      if (curLine.setEndPoint) {
        currentEnd = curLine.endPoint;
      }
      setCurrentLine({
        startPoint: currentStart,
        midPoint: new Vector3().addVectors(currentStart, currentEnd).multiplyScalar(0.5),
        endPoint: currentEnd,
        setStartPoint: curLine.setStartPoint,
        setEndPoint: curLine.setEndPoint
      });
      if (isPinching(rightHand, frame, refSpace)) {
        setCurrentLine((prev) => ({
          ...prev,
          setEndPoint: true
        }));
      }
      if (isPinching(leftHand, frame, refSpace)) {
        setCurrentLine((prev) => ({
          ...prev,
          setStartPoint: true
        }));
      }
      if (curLine.setStartPoint && curLine.setEndPoint) {
        setLines((prev) => [...prev, curLine]);
        setShowLine(false);
        setMeasureState(false);
        setDebounce(8);
      }
    } else if (debounceRef.current <= 0 && model.current && isPresenting) {
      const modelScene = model.current;
      modelScene.children[0].children.forEach((_childVal, childID) => {
        const child = modelScene.children[0].children[childID];
        const currentObjectBB = new Box3().setFromObject(child);
        const intersectsLeftTip = leftTipBB.intersectsBox(currentObjectBB);
        const intersectsRightTip = rightTipBB.intersectsBox(currentObjectBB);
        if (intersectsLeftTip || intersectsRightTip) {
          intersected = true;
          setObsHighlight(child.name);
          setHighlighted(true);
          if (intersectsLeftTip && isPinching(leftHand, frame, refSpace)) {
            setDebounce(10);
            intersected = false;
          }
          if (intersectsRightTip && isPinching(rightHand, frame, refSpace)) {
            setDebounce(10);
            intersected = false;
          }
        }
      });
      if (!intersected && highlightedRef.current) {
        setObsHighlight(null);
        setHighlighted(false);
      }
    }
  });
  const handlePointerDown = (e) => {
    if (!isPresenting)
      return;
    e.stopPropagation();
    e.target.setPointerCapture(e.pointerId);
    if (grabControllerRef.current === null) {
      grabControllerRef.current = e.pointerId;
      lastPointerPositions.current.set(e.pointerId, e.point.clone());
      if (rayGrabGroup.current) {
        initialScale.current = rayGrabGroup.current.scale.clone();
      }
    } else if (secondPointerId.current === null && e.pointerId !== grabControllerRef.current) {
      secondPointerId.current = e.pointerId;
      lastPointerPositions.current.set(e.pointerId, e.point.clone());
      const p1 = lastPointerPositions.current.get(grabControllerRef.current);
      const p2 = e.point;
      if (p1) {
        initialDistance.current = p1.distanceTo(p2);
      }
      if (rayGrabGroup.current) {
        initialScale.current = rayGrabGroup.current.scale.clone();
      }
    }
  };
  const handlePointerUp = (e) => {
    e.target.releasePointerCapture(e.pointerId);
    lastPointerPositions.current.delete(e.pointerId);
    if (grabControllerRef.current === e.pointerId) {
      grabControllerRef.current = null;
      initialScale.current = null;
    }
    if (secondPointerId.current === e.pointerId) {
      secondPointerId.current = null;
      initialDistance.current = 0;
    }
  };
  const handlePointerMove = (e) => {
    if (!rayGrabGroup.current || !e.point)
      return;
    const isFirstPointer = grabControllerRef.current === e.pointerId;
    const isSecondPointer = secondPointerId.current === e.pointerId;
    if (!isFirstPointer && !isSecondPointer)
      return;
    const prevPos = lastPointerPositions.current.get(e.pointerId);
    lastPointerPositions.current.set(e.pointerId, e.point.clone());
    if (secondPointerId.current !== null && initialDistance.current > 0 && initialScale.current) {
      const p1 = lastPointerPositions.current.get(grabControllerRef.current);
      const p2 = lastPointerPositions.current.get(secondPointerId.current);
      if (p1 && p2) {
        const currentDistance = p1.distanceTo(p2);
        const scaleFactor = currentDistance / initialDistance.current;
        rayGrabGroup.current.scale.copy(initialScale.current).multiplyScalar(scaleFactor);
      }
    } else if (isFirstPointer && prevPos) {
      const delta = e.point.clone().sub(prevPos);
      rayGrabGroup.current.position.add(delta);
    }
  };
  if (isPresenting) {
    return jsxs("group", { children: [jsxs("group", { ref: rayGrabGroup, onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerMove: handlePointerMove, children: [segmentationGroup?.visible ? jsxs("group", { children: [jsx("hemisphereLight", { color: 8421504, groundColor: 6316128 }), jsx("directionalLight", { color: 16777215, position: [0, -800, 0] }), jsx("primitive", { ref: model, object: segmentationGroup, position: [-0.18, 1.13, -1], scale: [
      2e-3 * segmentationSceneScale[0],
      2e-3 * segmentationSceneScale[1],
      2e-3 * segmentationSceneScale[2]
    ] })] }) : null, renderingSettings.uniforms && renderingSettings.shader && renderingSettings.meshScale ? jsx("group", { children: jsxs("mesh", { name: "cube", position: [-0.18, 1.13, -1], rotation: [0, 0, 0], scale: [
      2e-3 * renderingSettings.meshScale[0],
      2e-3 * renderingSettings.meshScale[1],
      2e-3 * renderingSettings.meshScale[2]
    ], ref: materialRef, children: [isValidGeometrySize(renderingSettings.geometrySize) && jsx("boxGeometry", { args: renderingSettings.geometrySize }), jsx("shaderMaterial", { customProgramCacheKey: () => "1", side: FrontSide, uniforms: renderingSettings.uniforms, needsUpdate: true, transparent: true, vertexShader: renderingSettings.shader.vertexShader, fragmentShader: renderingSettings.shader.fragmentShader })] }) }) : null] }), jsx("group", { name: "currentLine", ref: distanceRef, children: showLine ? jsx(MeasureLine, { currentLine, scale: 1 / 2e-3 * 0.4 }) : null }), jsx("group", { name: "lines", children: lines.map((object) => jsx(MeasureLine, { currentLine: object, scale: 1 / 2e-3 * 0.4 }, stringifyLineData(object))) })] });
  }
  return jsxs("group", { children: [jsxs("group", { children: [segmentationGroup?.visible ? jsxs("group", { children: [jsx("hemisphereLight", { color: 8421504, groundColor: 6316128 }), jsx("directionalLight", { color: 16777215, position: [0, -800, 0] }), jsx("directionalLight", { color: 16777215, position: [0, 800, 0] }), jsx(Bvh, { firstHitOnly: true, children: jsx("primitive", { ref: model, object: segmentationGroup, position: [0, 0, 0], onClick: (e) => {
    if (e.object.parent?.userData.name === "finalPass") {
      highlightEntity(e.object.name, e.object.userData.layerScope, e.object.userData.channelScope);
    }
  }, onPointerOver: (e) => {
    setObsHighlight(e.object.name);
  }, onPointerOut: () => setObsHighlight(null) }) })] }) : null, renderingSettings.uniforms && renderingSettings.shader && renderingSettings.meshScale && renderingSettings.geometrySize ? jsx("group", { children: jsxs("mesh", { scale: renderingSettings.meshScale, ref: materialRef, children: [jsx("boxGeometry", { args: renderingSettings.geometrySize }), jsx("shaderMaterial", { customProgramCacheKey: () => "1", side: FrontSide, uniforms: renderingSettings.uniforms, needsUpdate: true, transparent: true, vertexShader: renderingSettings.shader.vertexShader, fragmentShader: renderingSettings.shader.fragmentShader })] }) }) : null] }), jsx("group", { name: "lines", children: lines.map((object) => jsx(MeasureLine, { currentLine: object, scale: 1 }, stringifyLineData(object))) })] });
}
export {
  GeometryAndMeshXR as default
};
