import * as THREE from 'three'
import { useEffect, useMemo, useRef, useState } from 'react'
import { useThree } from '@react-three/fiber';
import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
import { useWallStore } from '../../../../store/builder/useWallStore';
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
import ReferencePoint from '../../point/reference/referencePoint';
import ReferenceWall from './referenceWall';

function WallCreator() {
    const { scene, camera, raycaster, gl, pointer } = useThree();
    const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
    const { toggleView } = useToggleView();
    const { toolMode } = useToolMode();
    const { activeLayer } = useActiveLayer();
    const { socket } = useSocketStore();
    const { addWall, getWallPointById } = useWallStore();
    const drag = useRef(false);
    const isLeftMouseDown = useRef(false);
    const { wallThickness, wallHeight, snappedPosition, snappedPoint } = useBuilderStore();

    const [tempPoints, setTempPoints] = useState<Point[]>([]);
    const [isCreating, setIsCreating] = useState(false);

    useEffect(() => {
        const canvasElement = gl.domElement;

        const onMouseDown = (evt: any) => {
            if (evt.button === 0) {
                isLeftMouseDown.current = true;
                drag.current = false;
            }
        };

        const onMouseUp = (evt: any) => {
            if (evt.button === 0) {
                isLeftMouseDown.current = false;
            }
        };

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

        const onMouseClick = () => {
            if (drag.current || !toggleView) return;

            raycaster.setFromCamera(pointer, camera);
            const intersectionPoint = new THREE.Vector3();
            let position = raycaster.ray.intersectPlane(plane, intersectionPoint);
            if (!position) return;

            const intersects = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Wall-Point');

            const newPoint: Point = {
                pointUuid: THREE.MathUtils.generateUUID(),
                pointType: 'Wall',
                position: [position.x, position.y, position.z],
                layer: activeLayer
            };

            if (snappedPosition && snappedPoint) {
                newPoint.pointUuid = snappedPoint.pointUuid;
                newPoint.position = snappedPosition;
                newPoint.layer = snappedPoint.layer;
            }

            if (snappedPosition && !snappedPoint) {
                newPoint.position = snappedPosition;
            }

            if (intersects && !snappedPoint) {
                const point = getWallPointById(intersects.object.uuid);
                if (point) {
                    newPoint.pointUuid = point.pointUuid;
                    newPoint.position = point.position;
                    newPoint.layer = point.layer;
                }
            }

            if (tempPoints.length === 0) {
                setTempPoints([newPoint]);
                setIsCreating(true);
            } else {
                const wall: Wall = {
                    wallUuid: THREE.MathUtils.generateUUID(),
                    points: [tempPoints[0], newPoint],
                    outSideMaterial: 'default',
                    inSideMaterial: 'default',
                    wallThickness: wallThickness,
                    wallHeight: wallHeight,
                    decals: []
                };
                addWall(wall);
                setTempPoints([newPoint]);
            }

        };

        const onContext = (event: any) => {
            event.preventDefault();
            if (isCreating) {
                setTempPoints([]);
                setIsCreating(false);
            }
        };

        if (toolMode === "Wall" && toggleView) {
            canvasElement.addEventListener("mousedown", onMouseDown);
            canvasElement.addEventListener("mouseup", onMouseUp);
            canvasElement.addEventListener("mousemove", onMouseMove);
            canvasElement.addEventListener("click", onMouseClick);
            canvasElement.addEventListener("contextmenu", onContext);
        } else {
            if (tempPoints.length > 0 || isCreating) {
                setTempPoints([]);
                setIsCreating(false);
            }
            canvasElement.removeEventListener("mousedown", onMouseDown);
            canvasElement.removeEventListener("mouseup", onMouseUp);
            canvasElement.removeEventListener("mousemove", onMouseMove);
            canvasElement.removeEventListener("click", onMouseClick);
            canvasElement.removeEventListener("contextmenu", onContext);
        }

        return () => {
            canvasElement.removeEventListener("mousedown", onMouseDown);
            canvasElement.removeEventListener("mouseup", onMouseUp);
            canvasElement.removeEventListener("mousemove", onMouseMove);
            canvasElement.removeEventListener("click", onMouseClick);
            canvasElement.removeEventListener("contextmenu", onContext);
        };
    }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addWall, getWallPointById, snappedPosition, snappedPoint]);

    return (
        <>
            {toggleView &&
                <>
                    <group name='Wall-Reference-Points-Group'>
                        {tempPoints.map((point) => (
                            <ReferencePoint key={point.pointUuid} point={point} />
                        ))}
                    </group>

                    {tempPoints.length > 0 &&
                        <ReferenceWall tempPoints={tempPoints} />
                    }
                </>
            }
        </>
    )
}

export default WallCreator