import * as THREE from 'three';
import { useEffect, useRef, useState } from 'react';
import { useThree, useFrame } from '@react-three/fiber';
import { useToolMode } from '../../../store/store';
import { Html } from '@react-three/drei';

const MeasurementTool = () => {
    const { gl, raycaster, pointer, camera, scene } = useThree();
    const { toolMode } = useToolMode();

    const [points, setPoints] = useState<THREE.Vector3[]>([]);
    const [tubeGeometry, setTubeGeometry] = useState<THREE.TubeGeometry | null>(null);
    const groupRef = useRef<THREE.Group>(null);
    const [startConePosition, setStartConePosition] = useState<THREE.Vector3 | null>(null);
    const [endConePosition, setEndConePosition] = useState<THREE.Vector3 | null>(null);
    const [startConeQuaternion, setStartConeQuaternion] = useState(new THREE.Quaternion());
    const [endConeQuaternion, setEndConeQuaternion] = useState(new THREE.Quaternion());
    const [coneSize, setConeSize] = useState({ radius: 0.2, height: 0.5 });


    const MIN_RADIUS = 0.001, MAX_RADIUS = 0.1;
    const MIN_CONE_RADIUS = 0.01, MAX_CONE_RADIUS = 0.4;
    const MIN_CONE_HEIGHT = 0.035, MAX_CONE_HEIGHT = 2.0;

    useEffect(() => {
        const canvasElement = gl.domElement;
        let drag = false;
        let isLeftMouseDown = false;

        const onMouseDown = () => {
            isLeftMouseDown = true;
            drag = false;
        };

        const onMouseUp = (evt: any) => {
            isLeftMouseDown = false;
            if (evt.button === 0 && !drag) {
                raycaster.setFromCamera(pointer, camera);
                const intersects = raycaster.intersectObjects(scene.children, true).filter(intersect => !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !intersect.object.name.includes("agv-collider") && !(intersect.object.type === "GridHelper"));

                if (intersects.length > 0) {
                    const intersectionPoint = intersects[0].point.clone();
                    if (points.length < 2) {
                        setPoints([...points, intersectionPoint]);
                    } else {
                        setPoints([intersectionPoint]);
                    }
                }
            }
        };

        const onMouseMove = () => {
            if (isLeftMouseDown) drag = true;
        };

        const onContextMenu = (evt: any) => {
            evt.preventDefault();
            if (!drag) {
                evt.preventDefault();
                setPoints([]);
                setTubeGeometry(null);
            }
        };

        if (toolMode === "MeasurementScale") {
            canvasElement.addEventListener("pointerdown", onMouseDown);
            canvasElement.addEventListener("pointermove", onMouseMove);
            canvasElement.addEventListener("pointerup", onMouseUp);
            canvasElement.addEventListener("contextmenu", onContextMenu);
        } else {
            resetMeasurement();
            setPoints([]);
        }

        return () => {
            canvasElement.removeEventListener("pointerdown", onMouseDown);
            canvasElement.removeEventListener("pointermove", onMouseMove);
            canvasElement.removeEventListener("pointerup", onMouseUp);
            canvasElement.removeEventListener("contextmenu", onContextMenu);
        };
    }, [toolMode, camera, raycaster, pointer, scene, points]);

    useFrame(() => {
        if (points.length === 1) {
            raycaster.setFromCamera(pointer, camera);
            const intersects = raycaster.intersectObjects(scene.children, true).filter(intersect => !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !intersect.object.name.includes("agv-collider") && !(intersect.object.type === "GridHelper"));

            if (intersects.length > 0) {
                updateMeasurement(points[0], intersects[0].point);
            }
        } else if (points.length === 2) {
            updateMeasurement(points[0], points[1]);
        } else {
            resetMeasurement();
        }
    });

    const updateMeasurement = (start: THREE.Vector3, end: THREE.Vector3) => {
        const distance = start.distanceTo(end);

        const radius = THREE.MathUtils.clamp(distance * 0.02, MIN_RADIUS, MAX_RADIUS);
        const coneRadius = THREE.MathUtils.clamp(distance * 0.05, MIN_CONE_RADIUS, MAX_CONE_RADIUS);
        const coneHeight = THREE.MathUtils.clamp(distance * 0.2, MIN_CONE_HEIGHT, MAX_CONE_HEIGHT);

        setConeSize({ radius: coneRadius, height: coneHeight });

        const direction = new THREE.Vector3().subVectors(end, start).normalize();

        const offset = direction.clone().multiplyScalar(coneHeight * 0.5);

        let tubeStart = start.clone().add(offset);
        let tubeEnd = end.clone().sub(offset);

        tubeStart.y = Math.max(tubeStart.y, 0);
        tubeEnd.y = Math.max(tubeEnd.y, 0);

        const curve = new THREE.CatmullRomCurve3([tubeStart, tubeEnd]);
        setTubeGeometry(new THREE.TubeGeometry(curve, 20, radius, 8, false));

        setStartConePosition(tubeStart);
        setEndConePosition(tubeEnd);
        setStartConeQuaternion(getArrowOrientation(start, end));
        setEndConeQuaternion(getArrowOrientation(end, start));
    };

    const resetMeasurement = () => {
        setTubeGeometry(null);
        setStartConePosition(null);
        setEndConePosition(null);
    };

    const getArrowOrientation = (start: THREE.Vector3, end: THREE.Vector3) => {
        const direction = new THREE.Vector3().subVectors(end, start).normalize().negate();
        const quaternion = new THREE.Quaternion();
        quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), direction);
        return quaternion;
    };

    useEffect(() => {
        if (points.length === 2) {
            console.log(points[0].distanceTo(points[1]));
        }
    }, [points])

    return (
        <group ref={groupRef} name="MeasurementGroup">
            {startConePosition && (
                <mesh name='MeasurementReference' position={startConePosition} quaternion={startConeQuaternion}>
                    <coneGeometry args={[coneSize.radius, coneSize.height, 16]} />
                    <meshBasicMaterial color="yellow" />
                </mesh>
            )}
            {endConePosition && (
                <mesh name='MeasurementReference' position={endConePosition} quaternion={endConeQuaternion}>
                    <coneGeometry args={[coneSize.radius, coneSize.height, 16]} />
                    <meshBasicMaterial color="yellow" />
                </mesh>
            )}
            {tubeGeometry && (
                <mesh name='MeasurementReference' geometry={tubeGeometry}>
                    <meshBasicMaterial color="yellow" />
                </mesh>
            )}

            {startConePosition && endConePosition && (
                <Html
                    as="div"
                    center
                    zIndexRange={[1, 0]}
                    style={{
                        padding: "10px",
                        color: "white",
                        borderRadius: "8px",
                        textAlign: "center",
                        fontFamily: "Arial, sans-serif",
                    }}
                    transform
                    sprite
                    scale={THREE.MathUtils.clamp(startConePosition.distanceTo(endConePosition) * 0.25, 0, 10)}
                    position={[(startConePosition.x + endConePosition.x) / 2, (startConePosition.y + endConePosition.y) / 2, (startConePosition.z + endConePosition.z) / 2]}
                >
                    <div style={{ color: "black" }} >{startConePosition.distanceTo(endConePosition).toFixed(2)} m</div>
                </Html>
            )}
        </group>
    );

};

export default MeasurementTool;
