import * as THREE from "three";
type PointData = {
  pointId: string;
  position: [number, number, number];
  isCurved: boolean;
  handleA: [number, number, number] | null;
  handleB: [number, number, number] | null;
};

interface PathDataInterface {
  pathId: string;
  pathPoints: [PointData, PointData]; // always two points
}

type PathData = PathDataInterface[];
export const POLYGON_CLOSE_THRESHOLD = 0.3;
export const SNAP_POINT_THRESHOLD = 0.2;
export const SNAP_LINE_THRESHOLD = 0.2;
export function handleMouseClick({
  evt,
  isDragging,
  raycaster,
  plane,
  pointer,
  currentTempPath,
  setCurrentTempPath,
  pathPointsList,
  allPaths,
  setAllPaths,
  addPointToCurrentTemp,
}: {
  evt: MouseEvent;
  isDragging: { current: boolean };
  raycaster: THREE.Raycaster;
  plane: THREE.Plane;
  pointer: { x: number; y: number };
  currentTempPath: any[];
  setCurrentTempPath: (val: any[]) => void;
  pathPointsList: any[];
  allPaths: any[];
  setAllPaths: React.Dispatch<React.SetStateAction<PathData>>;
  addPointToCurrentTemp: (point: any) => void;
}) {
  if (isDragging.current) return;
  if (evt.ctrlKey || evt.shiftKey) return;

  const intersectPoint = new THREE.Vector3();
  const pos = raycaster.ray.intersectPlane(plane, intersectPoint);
  if (!pos) return;

  let clickedPoint = new THREE.Vector3(pos.x, pos.y, pos.z);

  let snapPoint: any = null;
  for (let p of pathPointsList) {
    const pVec = new THREE.Vector3(...p.position);
    if (pVec.distanceTo(clickedPoint) < SNAP_POINT_THRESHOLD) {
      snapPoint = p;
      clickedPoint = pVec;
      break;
    }
  }

  let newPoint = snapPoint ?? {
    pointId: THREE.MathUtils.generateUUID(),
    position: [clickedPoint.x, 0, clickedPoint.z],
    isCurved: false,
    handleA: null,
    handleB: null,
  };

  if (currentTempPath.length > 2) {
    const firstVec = new THREE.Vector3(...currentTempPath[0].position);
    if (firstVec.distanceTo(clickedPoint) < POLYGON_CLOSE_THRESHOLD) {
      const closingPoint = { ...currentTempPath[0] };
      console.log("closingPoint: ", closingPoint);
      addPointToCurrentTemp(closingPoint);
      setCurrentTempPath([]);
      return;
    }
  }

  const getNearestPointOnLine = (
    a: THREE.Vector3,
    b: THREE.Vector3,
    p: THREE.Vector3
  ) => {
    const ab = new THREE.Vector3().subVectors(b, a);
    const t = Math.max(
      0,
      Math.min(1, p.clone().sub(a).dot(ab) / ab.lengthSq())
    );
    return a.clone().add(ab.multiplyScalar(t));
  };

  for (let path of allPaths) {
    const a = new THREE.Vector3(...path.pathPoints[0].position);
    const b = new THREE.Vector3(...path.pathPoints[1].position);
    const closest = getNearestPointOnLine(a, b, clickedPoint);

    if (closest.distanceTo(clickedPoint) < SNAP_LINE_THRESHOLD) {
      const splitPoint = {
        pointId: THREE.MathUtils.generateUUID(),
        position: closest.toArray() as [number, number, number],
        isCurved: false,
        handleA: null,
        handleB: null,
      };

      setAllPaths((prev: any) =>
        prev
          .filter((pa: any) => pa.pathId !== path.pathId)
          .concat([
            {
              pathId: THREE.MathUtils.generateUUID(),
              pathPoints: [path.pathPoints[0], splitPoint],
            },
            {
              pathId: THREE.MathUtils.generateUUID(),
              pathPoints: [splitPoint, path.pathPoints[1]],
            },
          ])
      );

      addPointToCurrentTemp(splitPoint);
      return;
    }
  }

  addPointToCurrentTemp(newPoint);
}
