import { useEffect, useRef, useState } from 'react';
import * as THREE from 'three';
import { useFrame, useThree } from '@react-three/fiber';
import { Html } from '@react-three/drei';
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
import { useActiveLayer, useToolMode, useToggleView } from '../../../../store/builder/store';
import { useDirectionalSnapping } from '../../point/helpers/useDirectionalSnapping';
import { usePointSnapping } from '../../point/helpers/usePointSnapping';
import * as Constants from '../../../../types/world/worldConstants';
import ReferenceLine from '../../line/reference/referenceLine';

interface ReferenceWallProps {
    tempPoints: Point[];
}

function ReferenceWall({ tempPoints }: Readonly<ReferenceWallProps>) {
    const { wallHeight, wallThickness, setSnappedPosition, setSnappedPoint } = useBuilderStore();

    const { pointer, raycaster, camera } = useThree();
    const { toolMode } = useToolMode();
    const { toggleView } = useToggleView();
    const { activeLayer } = useActiveLayer();
    const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
    const finalPosition = useRef<[number, number, number] | null>(null);

    const [tempWall, setTempWall] = useState<Wall | null>(null);
    const [currentPosition, setCurrentPosition] = useState<[number, number, number]>(tempPoints[0]?.position);

    const directionalSnap = useDirectionalSnapping(currentPosition, tempPoints[0]?.position || null);
    const { checkSnapForWall } = usePointSnapping({ uuid: 'temp-wall', pointType: 'Wall', position: directionalSnap.position || [0, 0, 0] });

    useFrame(() => {
        if (toolMode === 'Wall' && toggleView && tempPoints.length === 1) {
            raycaster.setFromCamera(pointer, camera);
            const intersectionPoint = new THREE.Vector3();
            raycaster.ray.intersectPlane(plane, intersectionPoint);

            setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);

            if (intersectionPoint) {
                const snapped = checkSnapForWall([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);

                if (snapped.isSnapped && snapped.snappedPoint) {
                    finalPosition.current = snapped.position;
                    setSnappedPosition(snapped.position);
                    setSnappedPoint(snapped.snappedPoint);
                } else if (directionalSnap.isSnapped) {
                    finalPosition.current = directionalSnap.position;
                    setSnappedPosition(directionalSnap.position);
                    setSnappedPoint(null);
                } else {
                    finalPosition.current = [intersectionPoint.x, intersectionPoint.y, intersectionPoint.z];
                    setSnappedPosition(null);
                    setSnappedPoint(null);
                }

                if (!finalPosition.current) return;

                const wallPoints: [Point, Point] = [
                    tempPoints[0],
                    {
                        pointUuid: 'temp-point',
                        pointType: 'Wall',
                        position: finalPosition.current,
                        layer: activeLayer,
                    }
                ];

                setTempWall({
                    wallUuid: 'temp-wall',
                    points: wallPoints,
                    outSideMaterial: 'default',
                    inSideMaterial: 'default',
                    wallThickness: wallThickness,
                    wallHeight: wallHeight,
                })

            }
        } else if (tempWall !== null) {
            setTempWall(null);
        }
    });

    useEffect(() => {
        setTempWall(null);
    }, [toolMode, toggleView, tempPoints.length, wallHeight, wallThickness]);

    if (!tempWall) return null;

    const renderWall = () => {
        return (
            <ReferenceLine points={tempWall.points} />
        )
    };

    const textPosition = new THREE.Vector3().addVectors(new THREE.Vector3(...tempWall.points[0].position), new THREE.Vector3(...tempWall.points[1].position)).divideScalar(2);
    const distance = new THREE.Vector3(...tempWall.points[0].position).distanceTo(new THREE.Vector3(...tempWall.points[1].position));

    const rendertext = () => {
        return (
            <>
                {toggleView && (
                    <Html
                        key={tempWall.wallUuid}
                        userData={tempWall}
                        position={[textPosition.x, 1, textPosition.z]}
                        wrapperClass="distance-text-wrapper"
                        className="distance-text"
                        zIndexRange={[1, 0]}
                        prepend
                        sprite
                    >
                        <div className={`distance ${tempWall.wallUuid}`}>{distance.toFixed(2)} m</div>
                    </Html>
                )}
            </>
        )
    }

    return (
        <group name="Wall-Reference-Group">
            {renderWall()}
            {rendertext()}
        </group>
    );
}

export default ReferenceWall;