import * as THREE from "three";
import { useParams } from "react-router-dom";
import { useThree } from "@react-three/fiber";
import { TransformControls } from "@react-three/drei";
import { useEffect, useRef, useState } from "react";
import { getUserData } from "../../../../functions/getUserData";
import { useSceneContext } from "../../sceneContext";
import { useObjectPosition, useObjectRotation, useActiveTool, useSocketStore } from "../../../../store/builder/store";
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";

import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
import { setAssetsApi } from "../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi";

export default function TransformControl() {
    const state = useThree();
    const ref = useRef(null);
    const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
    const { selectedFloorAsset, setSelectedFloorAsset } = useBuilderStore();
    const { setObjectPosition } = useObjectPosition();
    const { setObjectRotation } = useObjectRotation();
    const { activeTool } = useActiveTool();
    const { socket } = useSocketStore();
    const { assetStore, eventStore, productStore, undoRedo3DStore, versionStore } = useSceneContext();
    const { push3D } = undoRedo3DStore();
    const { updateAsset, getAssetById } = assetStore();
    const { userId, organization } = getUserData();
    const { selectedVersion } = versionStore();
    const { projectId } = useParams();

    const updateBackend = (productName: string, productUuid: string, projectId: string, eventData: EventsSchema) => {
        upsertProductOrEventApi({
            productName: productName,
            productUuid: productUuid,
            projectId: projectId,
            eventDatas: eventData,
            versionId: selectedVersion?.versionId || "",
        });
    };

    function handleObjectChange() {
        if (selectedFloorAsset) {
            setObjectPosition(selectedFloorAsset.position);
            setObjectRotation({
                x: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.x),
                y: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.y),
                z: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.z),
            });
        }
    }

    function handleMouseUp() {
        if (!productStore.getState().selectedProduct || !selectedFloorAsset) return;
        if (selectedFloorAsset) {
            setObjectPosition(selectedFloorAsset.position);
            setObjectRotation({
                x: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.x),
                y: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.y),
                z: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.z),
            });
        }
        const asset = getAssetById(selectedFloorAsset.uuid);
        if (asset) {
            if (asset.eventData) {
                const eventData = eventStore.getState().getEventByModelUuid(asset.modelUuid);
                const productData = productStore.getState().getEventByModelUuid(productStore.getState().selectedProduct.productUuid, asset.modelUuid);

                if (eventData) {
                    eventStore.getState().updateEvent(asset.modelUuid, {
                        position: [selectedFloorAsset.position.x, 0, selectedFloorAsset.position.z] as [number, number, number],
                        rotation: [selectedFloorAsset.rotation.x, selectedFloorAsset.rotation.y, selectedFloorAsset.rotation.z] as [number, number, number],
                    });
                }

                if (productData) {
                    const event = productStore.getState().updateEvent(productStore.getState().selectedProduct.productUuid, asset.modelUuid, {
                        position: [selectedFloorAsset.position.x, 0, selectedFloorAsset.position.z] as [number, number, number],
                        rotation: [selectedFloorAsset.rotation.x, selectedFloorAsset.rotation.y, selectedFloorAsset.rotation.z] as [number, number, number],
                    });

                    if (event) {
                        updateBackend(productStore.getState().selectedProduct.productName, productStore.getState().selectedProduct.productUuid, projectId || "", event);
                    }
                }
            }

            updateAsset(asset.modelUuid, {
                position: [selectedFloorAsset.position.x, 0, selectedFloorAsset.position.z],
                rotation: [selectedFloorAsset.rotation.x, selectedFloorAsset.rotation.y, selectedFloorAsset.rotation.z] as [number, number, number],
            });

            if (!socket?.connected) {
                // API

                setAssetsApi({
                    modelUuid: asset.modelUuid,
                    modelName: asset.modelName,
                    assetId: asset.assetId,
                    position: [selectedFloorAsset.position.x, 0, selectedFloorAsset.position.z] as [number, number, number],
                    rotation: { x: selectedFloorAsset.rotation.x, y: selectedFloorAsset.rotation.y, z: selectedFloorAsset.rotation.z },
                    isLocked: false,
                    isVisible: true,
                    versionId: selectedVersion?.versionId || "",
                    projectId: projectId,
                });
            } else {
                // SOCKET

                const data = {
                    organization,
                    modelUuid: asset.modelUuid,
                    modelName: asset.modelName,
                    assetId: asset.assetId,
                    position: [selectedFloorAsset.position.x, 0, selectedFloorAsset.position.z] as [number, number, number],
                    rotation: { x: selectedFloorAsset.rotation.x, y: selectedFloorAsset.rotation.y, z: selectedFloorAsset.rotation.z },
                    isLocked: false,
                    isVisible: true,
                    socketId: socket.id,
                    versionId: selectedVersion?.versionId || "",
                    userId,
                    projectId,
                };

                socket.emit("v1:model-asset:add", data);
            }

            push3D({
                type: "Scene",
                actions: [
                    {
                        module: "builder",
                        actionType: "Asset-Update",
                        asset: {
                            type: "Asset",
                            assetData: asset,
                            newData: {
                                ...asset,
                                position: [selectedFloorAsset.position.x, 0, selectedFloorAsset.position.z],
                                rotation: [selectedFloorAsset.rotation.x, selectedFloorAsset.rotation.y, selectedFloorAsset.rotation.z],
                            },
                            timeStap: new Date().toISOString(),
                        },
                    },
                ],
            });
        }
    }

    useEffect(() => {
        const handleKeyDown = (e: KeyboardEvent) => {
            const isTextInput = (element: Element | null): boolean => element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element?.getAttribute("contenteditable") === "true";
            if (isTextInput(document.activeElement)) return;
            const keyCombination = detectModifierKeys(e);
            if (!selectedFloorAsset) return;
            if (keyCombination === "G") {
                setTransformMode((prev) => (prev === "translate" ? null : "translate"));
            }
            if (keyCombination === "R") {
                setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
            }
        };

        if (selectedFloorAsset) {
            window.addEventListener("keydown", handleKeyDown);
            setObjectPosition(selectedFloorAsset.position);
            setObjectRotation({
                x: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.x),
                y: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.y),
                z: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.z),
            });
        } else {
            setTransformMode(null);
        }

        return () => {
            window.removeEventListener("keydown", handleKeyDown);
        };
    }, [selectedFloorAsset, setObjectPosition, setObjectRotation]);

    useEffect(() => {
        if (activeTool === "delete") {
            if (state.controls) {
                const target = (state.controls as any).getTarget(new THREE.Vector3());
                (state.controls as any).setTarget(target.x, 0, target.z, true);
            }
            setSelectedFloorAsset(null);
            setObjectPosition({ x: undefined, y: undefined, z: undefined });
            setObjectRotation({ x: undefined, y: undefined, z: undefined });
        }
    }, [activeTool, setObjectPosition, setObjectRotation, setSelectedFloorAsset, state.controls]);

    return <>{selectedFloorAsset && transformMode && <TransformControls ref={ref} showX={transformMode === "translate"} showY={transformMode === "rotate" || transformMode === "translate"} showZ={transformMode === "translate"} object={selectedFloorAsset} mode={transformMode} onObjectChange={handleObjectChange} onMouseUp={handleMouseUp} />}</>;
}
