import * as THREE from "three";
import { useCallback, useEffect, useRef } from "react";
import { ThreeEvent, useThree } from "@react-three/fiber";
import { useParams } from "react-router-dom";
import useModuleStore from "../../../../../../store/ui/useModuleStore";
import { useActiveTool, useToggleView } from "../../../../../../store/builder/store";
import { useSocketStore } from "../../../../../../store/socket/useSocketStore";
import { useSceneContext } from "../../../../../scene/sceneContext";
import { useBuilderStore } from "../../../../../../store/builder/useBuilderStore";
import useWallAssetResponseHandler from "../../../../../collaboration/responseHandler/useWallAssetResponseHandler";

import closestPointOnLineSegment from "../../../../line/helpers/getClosestPointOnLineSegment";
import { getUserData } from "../../../../../../functions/getUserData";

import { upsertWallAssetApi } from "../../../../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi";
import { deleteWallAssetApi } from "../../../../../../services/factoryBuilder/asset/wallAsset/deleteWallAssetApi";

export function useWallAssetEventHandler({ wallAsset, groupRef, wall }: { wallAsset: WallAsset; groupRef: React.RefObject<THREE.Group>; wall: Wall | undefined }) {
    const { builderSocket } = useSocketStore();
    const { raycaster, pointer, camera, scene, controls, gl } = useThree();
    const { wallAssetStore, versionStore } = useSceneContext();
    const { updateWallAsset, getWallAssetById } = wallAssetStore();
    const { toggleView } = useToggleView();
    const { activeTool } = useActiveTool();
    const { activeModule } = useModuleStore();
    const { selectedWallAsset, setSelectedWallAsset, setDeletableWallAsset, deletableWallAsset } = useBuilderStore();
    const { updateWallAssetInScene, removeWallAssetFromScene } = useWallAssetResponseHandler();
    const { selectedVersion } = versionStore();
    const { userId, organization } = getUserData();
    const { projectId } = useParams();

    const draggingRef = useRef(false);

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

        const onPointerUp = (e: PointerEvent) => {
            if (draggingRef.current) {
                draggingRef.current = false;
                if (controls) {
                    (controls as any).enabled = true;
                }

                if (selectedWallAsset) {
                    const updatedWallAsset = getWallAssetById(wallAsset.modelUuid);

                    if (projectId && updatedWallAsset) {
                        if (!builderSocket?.connected) {
                            // API

                            upsertWallAssetApi(projectId, selectedVersion?.versionId || "", updatedWallAsset)
                                .then((data) => {
                                    if (!data.message) {
                                        echo.error(`Error updating wallAsset ${updatedWallAsset.modelName} on the wall`);
                                        return;
                                    }
                                    if (data.message === "WallAsset Updated Successfully" && data.data) {
                                        updateWallAssetInScene(updatedWallAsset, () => {
                                            echo.log(`Updated wallAsset: ${updatedWallAsset.modelUuid} on the wall`);
                                        });
                                    } else {
                                        echo.error(`Error updating wallAsset ${updatedWallAsset.modelName} on the wall`);
                                    }
                                })
                                .catch(() => {
                                    echo.error(`Error updating wallAsset ${updatedWallAsset.modelName} on the wall`);
                                });
                        } else {
                            // SOCKET

                            const data = {
                                wallAssetData: updatedWallAsset,
                                projectId: projectId,
                                versionId: selectedVersion?.versionId || "",
                                userId: userId,
                                organization: organization,
                            };

                            builderSocket.emit("v1:wall-asset:add", data);
                        }
                    }
                }
            }
        };

        const onPointerMove = (e: any) => {
            if (!draggingRef.current || !wall || !selectedWallAsset) return;
            if (controls) {
                (controls as any).enabled = false;
            }

            pointer.x = (e.clientX / window.innerWidth) * 2 - 1;
            pointer.y = -(e.clientY / window.innerHeight) * 2 + 1;

            raycaster.setFromCamera(pointer, camera);
            const intersects = raycaster.intersectObjects(scene.children, true);
            const intersect = intersects.find((i: any) => i.object.name.includes("WallReference"));

            if (intersect?.object.userData.wallUuid) {
                const newPoint = closestPointOnLineSegment(
                    new THREE.Vector3(intersect.point.x, 0, intersect.point.z),
                    new THREE.Vector3(...intersect.object.userData.points[0].position),
                    new THREE.Vector3(...intersect.object.userData.points[1].position)
                );

                const wallRotation = intersect.object.rotation.clone();

                updateWallAsset(wallAsset.modelUuid, {
                    wallUuid: intersect.object.userData.wallUuid,
                    position: [newPoint.x, wallAsset.wallAssetType === "fixedMove" ? 0 : intersect.point.y, newPoint.z],
                    rotation: [wallRotation.x, wallRotation.y, wallRotation.z],
                });
            }
        };

        if (selectedWallAsset && !toggleView && activeModule === "builder") {
            canvasElement.addEventListener("mousemove", onPointerMove);
            canvasElement.addEventListener("pointerup", onPointerUp);
        }

        return () => {
            canvasElement.removeEventListener("mousemove", onPointerMove);
            canvasElement.removeEventListener("pointerup", onPointerUp);
        };
    }, [gl, camera, toggleView, activeModule, selectedWallAsset, builderSocket, wall, wallAsset]);

    const handlePointerEnter = useCallback(
        (evt: ThreeEvent<MouseEvent>) => {
            if (!toggleView) {
                evt.stopPropagation();
                let currentObject = evt.object;
                while (currentObject) {
                    if (currentObject.userData.wallUuid) {
                        break;
                    }
                    currentObject = currentObject.parent as THREE.Object3D;
                }
                if (activeTool === "delete" && activeModule === "builder") {
                    if (deletableWallAsset && deletableWallAsset.userData.modelUuid === wallAsset.modelUuid) {
                        return;
                    } else {
                        setDeletableWallAsset(currentObject);
                    }
                }
            }
        },
        [activeTool, activeModule, deletableWallAsset, toggleView]
    );

    const handlePointerLeave = useCallback(
        (evt: ThreeEvent<MouseEvent>) => {
            if (!toggleView) {
                evt.stopPropagation();
                if (evt.intersections.length === 0 && activeTool === "delete" && deletableWallAsset && deletableWallAsset.userData.modelUuid === wallAsset.modelUuid) {
                    setDeletableWallAsset(null);
                }
            }
        },
        [activeTool, deletableWallAsset, toggleView]
    );

    const handlePointerDown = useCallback(
        (e: ThreeEvent<MouseEvent>) => {
            if (!toggleView && activeModule === "builder" && selectedWallAsset && selectedWallAsset.userData.modelUuid === wallAsset.modelUuid) {
                draggingRef.current = true;
                e.stopPropagation();
                setSelectedWallAsset(groupRef.current);
                if (controls) {
                    (controls as any).enabled = false;
                }
            }
        },
        [toggleView, activeModule, selectedWallAsset, wallAsset]
    );

    const handleClick = useCallback(
        (e: ThreeEvent<MouseEvent>) => {
            if (!toggleView && activeModule === "builder" && activeTool !== "delete") {
                if (e.object) {
                    e.stopPropagation();
                    let currentObject = e.object;
                    while (currentObject) {
                        if (currentObject.userData.wallUuid) {
                            break;
                        }
                        currentObject = currentObject.parent as THREE.Object3D;
                    }
                    setSelectedWallAsset(currentObject);
                }
            } else if (!toggleView && activeModule === "builder" && activeTool === "delete") {
                if (activeTool === "delete" && deletableWallAsset && deletableWallAsset.userData.modelUuid === wallAsset.modelUuid) {
                    if (projectId) {
                        if (!builderSocket?.connected) {
                            // API

                            deleteWallAssetApi(projectId, selectedVersion?.versionId || "", wallAsset.modelUuid, wallAsset.wallUuid)
                                .then((data) => {
                                    if (!data.message || !data.data) {
                                        echo.error(`Error removing wallAsset from wall`);
                                        return;
                                    }
                                    if (data.message === "WallAsset Deleted Successfully") {
                                        removeWallAssetFromScene(wallAsset.modelUuid, () => {
                                            echo.log(`Removed wallAsset: ${wallAsset.modelName} along with wall`);
                                        });
                                    } else {
                                        echo.error(`Error removing wallAsset: ${wallAsset.modelName} from wall`);
                                    }
                                })
                                .catch(() => {
                                    echo.error(`Error removing wallAsset: ${wallAsset.modelName}`);
                                });
                        } else {
                            // SOCKET

                            const data = {
                                projectId: projectId,
                                versionId: selectedVersion?.versionId || "",
                                userId: userId,
                                organization: organization,
                                modelUuid: wallAsset.modelUuid,
                                wallUuid: wallAsset.wallUuid,
                            };
                            builderSocket.emit("v1:wall-asset:delete", data);
                        }
                    }
                }
            }
        },
        [toggleView, activeModule, activeTool, wallAsset, deletableWallAsset, builderSocket]
    );

    const handlePointerMissed = useCallback(() => {
        if (selectedWallAsset && selectedWallAsset.userData.modelUuid === wallAsset.modelUuid) {
            setSelectedWallAsset(null);
        }
    }, [selectedWallAsset, wallAsset]);

    return {
        handlePointerDown,
        handleClick,
        handlePointerMissed,
        handlePointerEnter,
        handlePointerLeave,
        draggingRef,
    };
}
