import { useEffect, useMemo, useRef, useState } from "react";
import { useThree } from "@react-three/fiber";
import * as THREE from "three";
import { Line } from "@react-three/drei";

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];
}

type PathData = PathDataInterface[];

interface LineSegmentProps {
  index: number;
  paths: PathDataInterface[];
  pathIndex: number;
  setPaths: React.Dispatch<React.SetStateAction<PathData>>;
  insertPoint?: (pathIndex: number, point: THREE.Vector3) => void;
}

export default function LineSegment({
  index,
  paths,
  setPaths,
  insertPoint,
  pathIndex,
}: LineSegmentProps) {
  const { gl, raycaster, camera, controls } = useThree();
  const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
  const [curve, setCurve] = useState<any>();
  const [curveState, setCurveState] = useState<string>("");

  const curvePoints = useMemo(() => {
    if (!paths || index >= paths.length) return [];

    const path = paths[index];
    const [current, next] = path.pathPoints;

    const start = new THREE.Vector3(...current.position);
    const end = new THREE.Vector3(...next.position);

    // 1️⃣ Case 1: use predefined handles
    const useCurve =
      (current.isCurved && current.handleB) || (next.isCurved && next.handleA);

    if (useCurve) {
      const hB = current.handleB
        ? new THREE.Vector3(...current.handleB)
        : start;
      const hA = next.handleA ? new THREE.Vector3(...next.handleA) : end;

      const curve = new THREE.CubicBezierCurve3(start, hB, hA, end);
      return curve.getPoints(100);
    }

    // 2️⃣ Case 2: use curveState-generated curve
    if (curveState) {
      const direction = new THREE.Vector3().subVectors(end, start).normalize();

      const up = new THREE.Vector3(0, 1, 0);
      const perpendicular = new THREE.Vector3()
        .crossVectors(direction, up)
        .normalize();

      const distance = start.distanceTo(end);
      const controlDistance = distance / 6;

      let controlPoint1, controlPoint2;

      // if (curveState === "arc") {
      //   const direction = new THREE.Vector3()
      //     .subVectors(end, start)
      //     .normalize();

      //   const perpendicular = new THREE.Vector3(
      //     -direction.z,
      //     0,
      //     direction.x
      //   ).normalize();

      //   controlPoint1 = new THREE.Vector3().addVectors(
      //     start,
      //     perpendicular.clone().multiplyScalar(-controlDistance) // negative fixes to "C"
      //   );

      //   controlPoint2 = new THREE.Vector3().addVectors(
      //     end,
      //     perpendicular.clone().multiplyScalar(-controlDistance)
      //   );
      // }
      if (curveState === "arc") {
        const direction = new THREE.Vector3()
          .subVectors(end, start)
          .normalize();

        // Perpendicular direction in XZ plane
        const perpendicular = new THREE.Vector3(-direction.z, 0, direction.x);

        const distance = start.distanceTo(end);
        const controlDistance = distance / 4;

        const controlPoint1 = new THREE.Vector3()
          .addVectors(start, direction.clone().multiplyScalar(distance / 3))
          .add(perpendicular.clone().multiplyScalar(-controlDistance)); // ← flipped

        const controlPoint2 = new THREE.Vector3()
          .addVectors(end, direction.clone().multiplyScalar(-distance / 3))
          .add(perpendicular.clone().multiplyScalar(-controlDistance)); // ← flipped

        const curve = new THREE.CubicBezierCurve3(
          start,
          controlPoint1,
          controlPoint2,
          end
        );
        return curve.getPoints(64);
      }

      // if (curveState === "arc") {
      //   const direction = new THREE.Vector3()
      //     .subVectors(end, start)
      //     .normalize();

      //   // XZ-plane perpendicular
      //   const perpendicular = new THREE.Vector3(-direction.z, 0, direction.x);

      //   const distance = start.distanceTo(end);
      //   const controlDistance = distance / 6; // ← increase this for more curvature

      //   const controlPoint1 = new THREE.Vector3().addVectors(
      //     start,
      //     perpendicular.clone().multiplyScalar(-controlDistance)
      //   );

      //   const controlPoint2 = new THREE.Vector3().addVectors(
      //     end,
      //     perpendicular.clone().multiplyScalar(-controlDistance)
      //   );

      //   const curve = new THREE.CubicBezierCurve3(
      //     start,
      //     controlPoint1,
      //     controlPoint2,
      //     end
      //   );
      //   return curve.getPoints(64);
      // }

      const curve = new THREE.CubicBezierCurve3(
        start,
        controlPoint1,
        controlPoint2,
        end
      );
      return curve.getPoints(32);
    }

    // 3️⃣ Case 3: fallback straight line
    const line = new THREE.LineCurve3(start, end);
    return line.getPoints(2);
  }, [paths, index, curveState]);

  // const curvePoints = useMemo(() => {
  //   if (!paths || index >= paths.length) return [];

  //   const path = paths[index];
  //   const [current, next] = path.pathPoints;

  //   const start = new THREE.Vector3(...current.position);
  //   const end = new THREE.Vector3(...next.position);

  //   // 1️⃣ Case 1: Use predefined curve handles if present
  //   const useCurve =
  //     (current.isCurved && current.handleB) || (next.isCurved && next.handleA);

  //   if (useCurve) {
  //     const handleB = current.handleB
  //       ? new THREE.Vector3(...current.handleB)
  //       : start;
  //     const handleA = next.handleA ? new THREE.Vector3(...next.handleA) : end;

  //     const curve = new THREE.CubicBezierCurve3(start, handleB, handleA, end);
  //     return curve.getPoints(100);
  //   }

  //   // 2️⃣ Case 2: Use curveState-generated arc (gentle C-shaped)
  //   // if (curveState === "arc") {
  //   //   const direction = new THREE.Vector3().subVectors(end, start).normalize();
  //   //   const distance = start.distanceTo(end);

  //   //   // Get perpendicular in XZ plane
  //   //   const perpendicular = new THREE.Vector3(-direction.z, 0, direction.x);

  //   //   const controlOffset = perpendicular.multiplyScalar(distance / 8);

  //   //   // Create gentle symmetric control points for a "C" arc
  //   //   const controlPoint1 = start.clone().add(controlOffset.clone().negate());
  //   //   const controlPoint2 = end.clone().add(controlOffset.clone().negate());

  //   //   const curve = new THREE.CubicBezierCurve3(
  //   //     start,
  //   //     controlPoint1,
  //   //     controlPoint2,
  //   //     end
  //   //   );

  //   //   return curve.getPoints(64); // 64 for smoother shape
  //   // }
  //   if (curveState === "arc") {
  //     const direction = new THREE.Vector3().subVectors(end, start).normalize();
  //     const distance = start.distanceTo(end);
  //     // const curveHeight = distance * 0.25; // 25% of distance

  //     // 🔺 Control height: Raise control points on Y-axis
  //     const curveHeight = distance / 4; // adjust 4 → higher = taller arc

  //     // Control points directly above the midpoint
  //     const mid = start.clone().add(end).multiplyScalar(0.5);
  //     const controlPoint = mid
  //       .clone()
  //       .add(new THREE.Vector3(0, curveHeight, 0));

  //     // Use Quadratic Bezier for simple arc
  //     const curve = new THREE.QuadraticBezierCurve3(start, controlPoint, end);
  //     return curve.getPoints(64);
  //   }

  //   // 3️⃣ Case 3: Fallback to straight line
  //   const line = new THREE.LineCurve3(start, end);
  //   return line.getPoints(2);
  // }, [paths, index, curveState]);

  const handleClick = (evt: any) => {
    if (evt.ctrlKey) {
      setCurveState("arc");
    }
  };
  // const bendFactor = 1 / 10; // tweak this dynamically
  // const controlOffset = perpendicular.multiplyScalar(distance * bendFactor);
  return (
    <Line
      points={curvePoints}
      color="purple"
      lineWidth={3.5}
      onClick={handleClick}
    />
  );
}
