import * as THREE from "three";
import { useEffect, useMemo } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { SkeletonUtils } from "three-stdlib";
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../../store/builder/store";
import * as Types from "../../../../../types/world/worldTypes";
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../../../functions/getUserData";
import { useSceneContext } from "../../../sceneContext";
import { useVersionContext } from "../../../../builder/version/versionContext";

// import { setAssetsApi } from '../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';

const CopyPasteControls3D = ({
    copiedObjects,
    setCopiedObjects,
    pastedObjects,
    setpastedObjects,
    selectionGroup,
    setDuplicatedObjects,
    movedObjects,
    setMovedObjects,
    rotatedObjects,
    setRotatedObjects,
    boundingBoxRef
}: any) => {
    const { camera, controls, gl, scene, pointer, raycaster } = useThree();
    const { toggleView } = useToggleView();
    const { selectedAssets, setSelectedAssets } = useSelectedAssets();
    const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
    const { socket } = useSocketStore();
    const { assetStore, eventStore } = useSceneContext();
    const { addEvent } = eventStore();
    const { projectId } = useParams();
    const { assets, addAsset } = assetStore();
    const { selectedVersionStore } = useVersionContext();
    const { selectedVersion } = selectedVersionStore();
    const { userId, organization } = getUserData();

    useEffect(() => {
        if (!camera || !scene || toggleView) return;
        const canvasElement = gl.domElement;
        canvasElement.tabIndex = 0;

        let isMoving = false;

        const onPointerDown = () => {
            isMoving = false;
        };

        const onPointerMove = () => {
            isMoving = true;
        };

        const onPointerUp = (event: PointerEvent) => {
            if (!isMoving && pastedObjects.length > 0 && event.button === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
                event.preventDefault();
                addPastedObjects();
            }
        };

        const onKeyDown = (event: KeyboardEvent) => {
            const keyCombination = detectModifierKeys(event);

            if (keyCombination === "Ctrl+C" && movedObjects.length === 0 && rotatedObjects.length === 0) {
                copySelection();
            }
            if (keyCombination === "Ctrl+V" && copiedObjects.length > 0 && pastedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
                pasteCopiedObjects();
            }
        };

        if (!toggleView) {
            canvasElement.addEventListener("pointerdown", onPointerDown);
            canvasElement.addEventListener("pointermove", onPointerMove);
            canvasElement.addEventListener("pointerup", onPointerUp);
            canvasElement.addEventListener("keydown", onKeyDown);
        }

        return () => {
            canvasElement.removeEventListener("pointerdown", onPointerDown);
            canvasElement.removeEventListener("pointermove", onPointerMove);
            canvasElement.removeEventListener("pointerup", onPointerUp);
            canvasElement.removeEventListener("keydown", onKeyDown);
        };

    }, [assets, camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, movedObjects, socket, rotatedObjects]);

    useFrame(() => {
        if (pastedObjects.length > 0) {
            const intersectionPoint = new THREE.Vector3();
            raycaster.setFromCamera(pointer, camera);
            const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
            if (point) {
                const position = new THREE.Vector3();
                if (boundingBoxRef.current) {
                    boundingBoxRef.current?.getWorldPosition(position)
                    selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
                } else {
                    const box = new THREE.Box3();
                    pastedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj.clone()));
                    const center = new THREE.Vector3();
                    box.getCenter(center);
                    selectionGroup.current.position.set(point.x - (center.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (center.z - selectionGroup.current.position.z));
                }
            }
        }
    });

    const copySelection = () => {
        if (selectedAssets.length > 0) {
            const newClones = selectedAssets.map((asset: any) => {
                const clone = SkeletonUtils.clone(asset);
                clone.position.copy(asset.position);
                return clone;
            });
            setCopiedObjects(newClones);
            echo.info("Objects copied!");
        }
    };

    const pasteCopiedObjects = () => {
        if (copiedObjects.length > 0 && pastedObjects.length === 0) {
            const newClones = copiedObjects.map((obj: THREE.Object3D) => {
                const clone = obj.clone();
                clone.position.copy(obj.position);
                return clone;
            });
            selectionGroup.current.add(...newClones);
            setpastedObjects([...newClones]);
            setSelectedAssets([...newClones]);

            const intersectionPoint = new THREE.Vector3();
            raycaster.setFromCamera(pointer, camera);
            const point = raycaster.ray.intersectPlane(plane, intersectionPoint);

            if (point) {
                const position = new THREE.Vector3();
                if (boundingBoxRef.current) {
                    boundingBoxRef.current?.getWorldPosition(position)
                    selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
                } else {
                    const box = new THREE.Box3();
                    newClones.forEach((obj: THREE.Object3D) => box.expandByObject(obj.clone()));
                    const center = new THREE.Vector3();
                    box.getCenter(center);
                    selectionGroup.current.position.set(point.x - (center.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (center.z - selectionGroup.current.position.z));
                }
            }
        }
    };

    const addPastedObjects = () => {
        if (pastedObjects.length === 0) return;

        pastedObjects.forEach(async (obj: THREE.Object3D) => {
            if (obj) {
                const worldPosition = new THREE.Vector3();
                obj.getWorldPosition(worldPosition);
                obj.position.copy(worldPosition);

                const newFloorItem: Types.FloorItemType = {
                    modelUuid: THREE.MathUtils.generateUUID(),
                    modelName: obj.userData.modelName,
                    assetId: obj.userData.assetId,
                    position: [worldPosition.x, worldPosition.y, worldPosition.z],
                    rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
                    isLocked: false,
                    isVisible: true,
                };

                let updatedEventData = null;

                if (obj.userData.eventData) {
                    updatedEventData = JSON.parse(JSON.stringify(obj.userData.eventData));
                    updatedEventData.modelUuid = newFloorItem.modelUuid;

                    const eventData: any = {
                        type: obj.userData.eventData.type,
                    };

                    if (obj.userData.eventData.type === "Conveyor") {
                        const ConveyorEvent: ConveyorEventSchema = {
                            modelUuid: newFloorItem.modelUuid,
                            modelName: newFloorItem.modelName,
                            position: newFloorItem.position,
                            rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
                            state: "idle",
                            type: 'transfer',
                            speed: 1,
                            points: updatedEventData.points.map((point: any, index: number) => ({
                                uuid: THREE.MathUtils.generateUUID(),
                                position: [point.position[0], point.position[1], point.position[2]],
                                rotation: [point.rotation[0], point.rotation[1], point.rotation[2]],
                                action: {
                                    actionUuid: THREE.MathUtils.generateUUID(),
                                    actionName: `Action 1`,
                                    actionType: 'default',
                                    material: 'Default Material',
                                    delay: 0,
                                    spawnInterval: 5,
                                    spawnCount: 1,
                                    triggers: []
                                }
                            }))
                        };
                        addEvent(ConveyorEvent);
                        eventData.points = ConveyorEvent.points.map(point => ({
                            uuid: point.uuid,
                            position: point.position,
                            rotation: point.rotation
                        }));

                    } else if (obj.userData.eventData.type === "Vehicle") {
                        const vehicleEvent: VehicleEventSchema = {
                            modelUuid: newFloorItem.modelUuid,
                            modelName: newFloorItem.modelName,
                            position: newFloorItem.position,
                            rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
                            state: "idle",
                            type: "vehicle",
                            speed: 1,
                            point: {
                                uuid: THREE.MathUtils.generateUUID(),
                                position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
                                rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
                                action: {
                                    actionUuid: THREE.MathUtils.generateUUID(),
                                    actionName: "Action 1",
                                    actionType: "travel",
                                    unLoadDuration: 5,
                                    loadCapacity: 1,
                                    steeringAngle: 0,
                                    pickUpPoint: null,
                                    unLoadPoint: null,
                                    paths: {
                                        initPickup: [],
                                        pickupDrop: [],
                                        dropPickup: [],
                                    },
                                    triggers: []
                                }
                            }
                        };
                        addEvent(vehicleEvent);
                        eventData.point = {
                            uuid: vehicleEvent.point.uuid,
                            position: vehicleEvent.point.position,
                            rotation: vehicleEvent.point.rotation
                        };

                    } else if (obj.userData.eventData.type === "ArmBot") {
                        const roboticArmEvent: RoboticArmEventSchema = {
                            modelUuid: newFloorItem.modelUuid,
                            modelName: newFloorItem.modelName,
                            position: newFloorItem.position,
                            rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
                            state: "idle",
                            type: "roboticArm",
                            speed: 1,
                            point: {
                                uuid: THREE.MathUtils.generateUUID(),
                                position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
                                rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
                                actions: [
                                    {
                                        actionUuid: THREE.MathUtils.generateUUID(),
                                        actionName: "Action 1",
                                        actionType: "pickAndPlace",
                                        process: {
                                            startPoint: null,
                                            endPoint: null
                                        },
                                        triggers: []
                                    }
                                ]
                            }
                        };
                        addEvent(roboticArmEvent);
                        eventData.point = {
                            uuid: roboticArmEvent.point.uuid,
                            position: roboticArmEvent.point.position,
                            rotation: roboticArmEvent.point.rotation
                        };

                    } else if (obj.userData.eventData.type === "StaticMachine") {
                        const machineEvent: MachineEventSchema = {
                            modelUuid: newFloorItem.modelUuid,
                            modelName: newFloorItem.modelName,
                            position: newFloorItem.position,
                            rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
                            state: "idle",
                            type: "machine",
                            point: {
                                uuid: THREE.MathUtils.generateUUID(),
                                position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
                                rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
                                action: {
                                    actionUuid: THREE.MathUtils.generateUUID(),
                                    actionName: "Action 1",
                                    actionType: "process",
                                    processTime: 10,
                                    swapMaterial: "Default Material",
                                    triggers: []
                                }
                            }
                        };
                        addEvent(machineEvent);
                        eventData.point = {
                            uuid: machineEvent.point.uuid,
                            position: machineEvent.point.position,
                            rotation: machineEvent.point.rotation
                        };
                    } else if (obj.userData.eventData.type === "Storage") {
                        const storageEvent: StorageEventSchema = {
                            modelUuid: newFloorItem.modelUuid,
                            modelName: newFloorItem.modelName,
                            position: newFloorItem.position,
                            rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
                            state: "idle",
                            type: "storageUnit",
                            point: {
                                uuid: THREE.MathUtils.generateUUID(),
                                position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
                                rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
                                action: {
                                    actionUuid: THREE.MathUtils.generateUUID(),
                                    actionName: "Action 1",
                                    actionType: "store",
                                    storageCapacity: 10,
                                    triggers: []
                                }
                            }
                        }
                        addEvent(storageEvent);
                        eventData.point = {
                            uuid: storageEvent.point.uuid,
                            position: storageEvent.point.position,
                            rotation: storageEvent.point.rotation
                        };
                    } else if (obj.userData.eventData.type === "Human") {
                        const humanEvent: HumanEventSchema = {
                            modelUuid: newFloorItem.modelUuid,
                            modelName: newFloorItem.modelName,
                            position: newFloorItem.position,
                            rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
                            state: "idle",
                            type: "human",
                            speed: 1,
                            point: {
                                uuid: THREE.MathUtils.generateUUID(),
                                position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
                                rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
                                actions: [
                                    {
                                        actionUuid: THREE.MathUtils.generateUUID(),
                                        actionName: "Action 1",
                                        actionType: "worker",
                                        loadCapacity: 1,
                                        loadCount: 1,
                                        processTime: 10,
                                        triggers: []
                                    }
                                ]
                            }
                        }
                        addEvent(humanEvent);
                        eventData.point = {
                            uuid: humanEvent.point.uuid,
                            position: humanEvent.point.position,
                            rotation: humanEvent.point.rotation
                        };
                    }

                    newFloorItem.eventData = eventData;
                    //REST

                    // await setAssetsApi(
                    //     organization,
                    //     obj.uuid,
                    //     obj.userData.name,
                    //     [worldPosition.x, worldPosition.y, worldPosition.z],
                    //     { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
                    //     obj.userData.modelId,
                    //     false,
                    //     true,
                    // );

                    //SOCKET

                    const data = {
                        organization,
                        modelUuid: newFloorItem.modelUuid,
                        modelName: newFloorItem.modelName,
                        assetId: newFloorItem.assetId,
                        position: newFloorItem.position,
                        rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
                        isLocked: false,
                        isVisible: true,
                        socketId: socket.id,
                        eventData: eventData,
                        versionId: selectedVersion?.versionId || '',
                        userId,
                        projectId
                    };

                    // console.log('data: ', data);
                    socket.emit("v1:model-asset:add", data);

                    obj.userData = {
                        name: newFloorItem.modelName,
                        modelId: newFloorItem.assetId,
                        modelUuid: newFloorItem.modelUuid,
                        eventData: JSON.parse(JSON.stringify(eventData))
                    };

                    const asset: Asset = {
                        modelUuid: data.modelUuid,
                        modelName: data.modelName,
                        assetId: data.assetId,
                        position: data.position,
                        rotation: [data.rotation.x, data.rotation.y, data.rotation.z],
                        isLocked: data.isLocked,
                        isCollidable: false,
                        isVisible: data.isVisible,
                        opacity: 1,
                        eventData: data.eventData
                    }

                    addAsset(asset);

                } else {

                    //REST

                    // await setAssetsApi(
                    //     organization,
                    //     obj.uuid,
                    //     obj.userData.name,
                    //     [worldPosition.x, worldPosition.y, worldPosition.z],
                    //     { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
                    //     obj.userData.modelId,
                    //     false,
                    //     true,
                    // );

                    //SOCKET
                    const data = {
                        organization,
                        modelUuid: newFloorItem.modelUuid,
                        modelName: newFloorItem.modelName,
                        assetId: newFloorItem.assetId,
                        position: newFloorItem.position,
                        rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
                        isLocked: false,
                        isVisible: true,
                        socketId: socket.id,
                        versionId: selectedVersion?.versionId || '',
                        projectId,
                        userId
                    };

                    // console.log('data: ', data);
                    socket.emit("v1:model-asset:add", data);

                    const asset: Asset = {
                        modelUuid: data.modelUuid,
                        modelName: data.modelName,
                        assetId: data.assetId,
                        position: data.position,
                        rotation: [data.rotation.x, data.rotation.y, data.rotation.z],
                        isLocked: data.isLocked,
                        isCollidable: false,
                        isVisible: data.isVisible,
                        opacity: 1,
                    }

                    addAsset(asset);
                }
            }
        });

        echo.success("Object added!");
        clearSelection();
    };

    const clearSelection = () => {
        selectionGroup.current.children = [];
        selectionGroup.current.position.set(0, 0, 0);
        selectionGroup.current.rotation.set(0, 0, 0);
        setMovedObjects([]);
        setpastedObjects([]);
        setDuplicatedObjects([]);
        setRotatedObjects([]);
        setSelectedAssets([]);
    }

    return null;
};

export default CopyPasteControls3D;