import { useEffect, useState } from "react";
import { MathUtils } from "three";

import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from "../trigger/Trigger";
import ActionsList from "../components/ActionsList";
import WorkerAction from "../actions/workerAction";
import AssemblyAction from "../actions/assemblyAction";

import { useSelectedEventData, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
import { useVersionContext } from "../../../../../../modules/builder/version/versionContext";
import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
import { useParams } from "react-router-dom";

function HumanMechanics() {
    const [activeOption, setActiveOption] = useState<"worker" | "assembly">("worker");
    const [speed, setSpeed] = useState("0.5");
    const [loadCount, setLoadCount] = useState(0);
    const [loadCapacity, setLoadCapacity] = useState("1");
    const [processTime, setProcessTime] = useState(10);
    const [swappedMaterial, setSwappedMaterial] = useState("Default material");
    const [currentAction, setCurrentAction] = useState<HumanAction | undefined>();
    const [selectedPointData, setSelectedPointData] = useState<HumanPointSchema | undefined>();
    const { selectedEventData } = useSelectedEventData();
    const { productStore } = useSceneContext();
    const { getPointByUuid, updateEvent, updateAction, addAction, removeAction, getEventByModelUuid, getActionByUuid } = productStore();
    const { selectedProductStore } = useProductContext();
    const { selectedProduct } = selectedProductStore();
    const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction();
    const { selectedVersionStore } = useVersionContext();
    const { selectedVersion } = selectedVersionStore();
    const { projectId } = useParams();

    useEffect(() => {
        if (selectedEventData && selectedEventData.data.type === "human") {
            const point = getPointByUuid(
                selectedProduct.productUuid,
                selectedEventData.data.modelUuid,
                selectedEventData.selectedPoint
            ) as HumanPointSchema | undefined;

            if (point?.actions?.length) {
                setSelectedPointData(point);
                const firstAction = point.actions[0];
                setCurrentAction(firstAction);
                setSpeed((
                    getEventByModelUuid(
                        selectedProduct.productUuid,
                        selectedEventData?.data.modelUuid || ""
                    ) as HumanEventSchema | undefined
                )?.speed?.toString() || "1");
                setLoadCapacity(firstAction.loadCapacity.toString());
                setActiveOption(firstAction.actionType);
                setLoadCount(firstAction.loadCount || 0);
                setProcessTime(firstAction.processTime || 10);
                setSwappedMaterial(firstAction.swapMaterial || "Default material");
            }
        } else {
            clearSelectedAction();
        }
    }, [selectedEventData, selectedProduct]);

    useEffect(() => {
        if (selectedEventData && selectedEventData.data.type === "human") {
            const point = getPointByUuid(
                selectedProduct.productUuid,
                selectedEventData.data.modelUuid,
                selectedEventData.selectedPoint
            ) as HumanPointSchema | undefined;

            const actionUuid = selectedAction.actionId || point?.actions[0].actionUuid || '';

            const newCurrentAction = getActionByUuid(selectedProduct.productUuid, actionUuid);

            if (newCurrentAction && (newCurrentAction.actionType === 'assembly' || newCurrentAction?.actionType === 'worker')) {
                if (!selectedAction.actionId) {
                    setSelectedAction(newCurrentAction.actionUuid, newCurrentAction.actionName);
                }
                setCurrentAction(newCurrentAction);
                setActiveOption(newCurrentAction.actionType);
                setLoadCapacity(newCurrentAction.loadCapacity.toString());
                setLoadCount(newCurrentAction.loadCount || 0);

                if (newCurrentAction.actionType === 'assembly') {
                    setProcessTime(newCurrentAction.processTime || 10);
                    setSwappedMaterial(newCurrentAction.swapMaterial || "Default material");
                }
            } else {
                clearSelectedAction();
                setCurrentAction(undefined);
            }
        }
    }, [selectedAction, selectedProduct, selectedEventData]);

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

    const handleSelectActionType = (actionType: string) => {
        if (!selectedAction.actionId || !currentAction || !selectedPointData) return;

        const updatedAction = { ...currentAction, actionType: actionType as "worker" | "assembly" };
        const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action);
        const updatedPoint = { ...selectedPointData, actions: updatedActions };

        const event = updateAction(
            selectedProduct.productUuid,
            selectedAction.actionId,
            updatedAction
        );

        if (event) {
            updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
        }

        setCurrentAction(updatedAction);
        setSelectedPointData(updatedPoint);
    };

    const handleSpeedChange = (value: string) => {
        if (!selectedEventData) return;

        const numericValue = parseFloat(value);
        if (isNaN(numericValue)) return;

        const updatedEvent = {
            ...selectedEventData.data,
            speed: numericValue
        } as HumanEventSchema;

        const event = updateEvent(
            selectedProduct.productUuid,
            selectedEventData.data.modelUuid,
            updatedEvent
        );

        if (event) {
            updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
        }

        setSpeed(value);
    };

    const handleLoadCapacityChange = (value: string) => {
        if (!currentAction || !selectedPointData || !selectedAction.actionId) return;

        const updatedAction = { ...currentAction, loadCapacity: parseInt(value) };
        const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action);
        const updatedPoint = { ...selectedPointData, actions: updatedActions };

        const event = updateAction(
            selectedProduct.productUuid,
            selectedAction.actionId,
            updatedAction
        );

        if (event) {
            updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
        }

        setCurrentAction(updatedAction);
        setSelectedPointData(updatedPoint);
        setLoadCapacity(value);
    };

    const handleLoadCountChange = (value: number) => {
        if (!currentAction || !selectedPointData || !selectedAction.actionId) return;

        const updatedAction = { ...currentAction, loadCount: value };
        const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action);
        const updatedPoint = { ...selectedPointData, actions: updatedActions };

        const event = updateAction(
            selectedProduct.productUuid,
            selectedAction.actionId,
            updatedAction
        );

        if (event) {
            updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
        }

        setCurrentAction(updatedAction);
        setSelectedPointData(updatedPoint);
        setLoadCount(value);
    };

    const handleProcessTimeChange = (value: number) => {
        if (!currentAction || !selectedPointData || !selectedAction.actionId) return;

        const updatedAction = { ...currentAction, processTime: value };
        const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action);
        const updatedPoint = { ...selectedPointData, actions: updatedActions };

        const event = updateAction(
            selectedProduct.productUuid,
            selectedAction.actionId,
            updatedAction
        );

        if (event) {
            updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
        }

        setCurrentAction(updatedAction);
        setSelectedPointData(updatedPoint);
        setProcessTime(value);
    };

    const handleMaterialChange = (value: string) => {
        if (!currentAction || !selectedPointData || !selectedAction.actionId) return;

        const updatedAction = { ...currentAction, swapMaterial: value };
        const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action);
        const updatedPoint = { ...selectedPointData, actions: updatedActions };

        const event = updateAction(
            selectedProduct.productUuid,
            selectedAction.actionId,
            updatedAction
        );

        if (event) {
            updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
        }

        setCurrentAction(updatedAction);
        setSelectedPointData(updatedPoint);
        setSwappedMaterial(value);
    };

    const handleClearPoints = () => {
        if (!currentAction || !selectedPointData || !selectedAction.actionId) return;

        const updatedAction: HumanAction = JSON.parse(JSON.stringify(currentAction));

        if (updatedAction.actionType === 'assembly') {
            updatedAction.assemblyPoint = { position: null, rotation: null, }
        } else {
            updatedAction.pickUpPoint = { position: null, rotation: null, };
            updatedAction.dropPoint = { position: null, rotation: null, }
        }

        const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action);
        const updatedPoint = { ...selectedPointData, actions: updatedActions };

        const event = updateAction(
            selectedProduct.productUuid,
            selectedAction.actionId,
            updatedAction
        );

        if (event) {
            updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
        }

        setCurrentAction(updatedAction);
        setSelectedPointData(updatedPoint);
    };

    const handleAddAction = () => {
        if (!selectedEventData || !selectedPointData) return;

        const newAction: HumanAction = {
            actionUuid: MathUtils.generateUUID(),
            actionName: `Action  ${selectedPointData.actions.length + 1}`,
            actionType: "worker",
            loadCount: 1,
            loadCapacity: 1,
            processTime: 10,
            triggers: [],
        };

        const updatedActions = [...(selectedPointData.actions || []), newAction];
        const updatedPoint = { ...selectedPointData, actions: updatedActions };

        const event = addAction(
            selectedProduct.productUuid,
            selectedEventData.data.modelUuid,
            selectedEventData.selectedPoint,
            newAction
        );

        if (event) {
            updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
        }

        setSelectedPointData(updatedPoint);
        setSelectedAction(newAction.actionUuid, newAction.actionName);
    };

    const handleDeleteAction = () => {
        if (!selectedPointData || !selectedAction.actionId) return;

        const updatedActions = selectedPointData.actions.filter(action => action.actionUuid !== selectedAction.actionId);
        const updatedPoint = { ...selectedPointData, actions: updatedActions };

        const event = removeAction(
            selectedProduct.productUuid,
            selectedAction.actionId
        );

        if (event) {
            updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
        }

        setSelectedPointData(updatedPoint);

        const index = selectedPointData.actions.findIndex((a) => a.actionUuid === selectedAction.actionId);
        const nextAction = updatedPoint.actions[index] || updatedPoint.actions[index - 1];
        if (nextAction) {
            setSelectedAction(nextAction.actionUuid, nextAction.actionName);
            const action = getActionByUuid(selectedProduct.productUuid, nextAction.actionUuid);
            if (action) {
                setCurrentAction(action as HumanAction);
            }
        } else {
            clearSelectedAction();
            setCurrentAction(undefined);
        }
    };

    return (
        <>
            <div className="global-props section">
                <div className="property-list-container">
                    <div className="property-item">
                        <InputWithDropDown
                            label="Speed"
                            value={speed}
                            min={0}
                            step={0.1}
                            defaultValue="0.5"
                            max={10}
                            activeOption="m/s"
                            onClick={() => { }}
                            onChange={handleSpeedChange}
                        />
                    </div>
                </div>
            </div>
            <section>
                <ActionsList
                    selectedPointData={selectedPointData}
                    multipleAction={true}
                    handleAddAction={handleAddAction}
                    handleDeleteAction={handleDeleteAction}
                />

                {selectedAction.actionId && currentAction && (
                    <div className="selected-actions-details">
                        <div className="selected-actions-header">
                            <RenameInput value={selectedAction.actionName || ""} canEdit={false} />
                        </div>
                        <div className="selected-actions-list">
                            <LabledDropdown
                                label="Action Type"
                                defaultOption={activeOption}
                                options={["worker", "assembly"]}
                                onSelect={handleSelectActionType}
                                disabled={false}
                            />
                        </div>
                        {currentAction.actionType === 'worker' &&
                            <WorkerAction
                                loadCapacity={{
                                    value: loadCapacity,
                                    min: 1,
                                    max: 20,
                                    step: 1,
                                    defaultValue: "1",
                                    disabled: true,
                                    onChange: handleLoadCapacityChange,
                                }}
                                loadCount={{
                                    value: loadCount,
                                    min: 0,
                                    max: 20,
                                    step: 1,
                                    defaultValue: "1",
                                    disabled: false,
                                    onChange: handleLoadCountChange,
                                }}
                                clearPoints={handleClearPoints}
                            />
                        }
                        {currentAction.actionType === 'assembly' &&
                            <AssemblyAction
                                processTime={{
                                    value: processTime,
                                    min: 1,
                                    max: 60,
                                    onChange: handleProcessTimeChange,
                                }}
                                swapOptions={["Default material", "Material 1", "Material 2", "Material 3"]}
                                swapDefaultOption={swappedMaterial}
                                onSwapSelect={handleMaterialChange}
                                clearPoints={handleClearPoints}
                            />
                        }
                        <div className="tirgger">
                            <Trigger selectedPointData={selectedPointData as any} type="Human" />
                        </div>
                    </div>
                )}
            </section>
        </>
    );
}

export default HumanMechanics;