import React, { useCallback, useEffect, useRef, useState } from 'react';
import VehicleAnimator from '../animator/vehicleAnimator';
import * as THREE from 'three';
import { NavMeshQuery } from '@recast-navigation/core';
import { useNavMesh } from '../../../../../store/builder/store';
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore';
import { useConveyorStore } from '../../../../../store/simulation/useConveyorStore';
import { useStorageUnitStore } from '../../../../../store/simulation/useStorageUnitStore';
import { useMaterialStore } from '../../../../../store/simulation/useMaterialStore';
import { useProductStore } from '../../../../../store/simulation/useProductStore';
import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore';
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
import MaterialAnimator from '../animator/materialAnimator';
type Timer = {
    start: number | null;
    active: boolean;
};
function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) {
    const { navMesh } = useNavMesh();
    const { isPlaying } = usePlayButtonStore();
    const { removeMaterial, setEndTime } = useMaterialStore();
    const { getStorageUnitById } = useStorageUnitStore();
    const { getArmBotById } = useArmBotStore();
    const { getConveyorById } = useConveyorStore();
    const { triggerPointActions } = useTriggerHandler();
    const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = useProductStore();
    const { selectedProduct } = useSelectedProduct();
    const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial, getLastMaterial } = useVehicleStore();
    const [currentPhase, setCurrentPhase] = useState<string>('stationed');
    const [path, setPath] = useState<[number, number, number][]>([]);
    const pauseTimeRef = useRef<number | null>(null);
    const isPausedRef = useRef<boolean>(false);
    let startTime: number;
    let fixedInterval: number;
    const { speed } = useAnimationPlaySpeed();
    const { isPaused } = usePauseButtonStore();

    useEffect(() => {
        isPausedRef.current = isPaused;
    }, [isPaused]);

    const computePath = useCallback(
        (start: any, end: any) => {
            try {
                const navMeshQuery = new NavMeshQuery(navMesh);
                const { path: segmentPath } = navMeshQuery.computePath(start, end);
                return (
                    segmentPath?.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || []
                );
            } catch {
                echo.error("Failed to compute path");
                return [];
            }
        },
        [navMesh]
    );

    function vehicleStatus(modelId: string, status: string) {
        // 
    }

    // Function to reset everything
    function reset() {
        setCurrentPhase('stationed');
        setVehicleActive(agvDetail.modelUuid, false);
        setVehiclePicking(agvDetail.modelUuid, false);
        setVehicleState(agvDetail.modelUuid, 'idle');
        setVehicleLoad(agvDetail.modelUuid, 0);
        setPath([]);
        startTime = 0;
        isPausedRef.current = false;
        pauseTimeRef.current = 0;
    }

    useEffect(() => {
        if (isPlaying) {
            if (!agvDetail.point.action.unLoadPoint || !agvDetail.point.action.pickUpPoint) return;

            if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') {
                const toPickupPath = computePath(
                    new THREE.Vector3(agvDetail?.position[0], agvDetail?.position[1], agvDetail?.position[2]),
                    agvDetail?.point?.action?.pickUpPoint?.position
                );
                setPath(toPickupPath);
                setCurrentPhase('stationed-pickup');
                setVehicleState(agvDetail.modelUuid, 'running');
                setVehiclePicking(agvDetail.modelUuid, false);
                setVehicleActive(agvDetail.modelUuid, true);
                vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup');
                return;
            } else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'picking') {
                if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity && agvDetail.currentMaterials.length > 0) {
                    if (agvDetail.point.action.pickUpPoint && agvDetail.point.action.unLoadPoint) {
                        const toDrop = computePath(
                            agvDetail.point.action.pickUpPoint.position,
                            agvDetail.point.action.unLoadPoint.position
                        );
                        setPath(toDrop);
                        setCurrentPhase('pickup-drop');
                        setVehicleState(agvDetail.modelUuid, 'running');
                        setVehiclePicking(agvDetail.modelUuid, false);
                        setVehicleActive(agvDetail.modelUuid, true);
                        vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point');
                    }
                }
            } else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'dropping' && agvDetail.currentLoad === 0) {
                if (agvDetail.point.action.pickUpPoint && agvDetail.point.action.unLoadPoint) {
                    const dropToPickup = computePath(
                        agvDetail.point.action.unLoadPoint.position,
                        agvDetail.point.action.pickUpPoint.position
                    );
                    setPath(dropToPickup);
                    setCurrentPhase('drop-pickup');
                    setVehicleState(agvDetail.modelUuid, 'running');
                    setVehiclePicking(agvDetail.modelUuid, false);
                    setVehicleActive(agvDetail.modelUuid, true);
                    vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point');
                }
            }
        } else {
            reset()
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [vehicles, currentPhase, path, isPlaying]);

    function handleCallBack() {
        if (currentPhase === 'stationed-pickup') {
            setCurrentPhase('picking');
            setVehicleState(agvDetail.modelUuid, 'idle');
            setVehiclePicking(agvDetail.modelUuid, true);
            setVehicleActive(agvDetail.modelUuid, false);
            vehicleStatus(agvDetail.modelUuid, 'Reached pickup point, waiting for material');
            setPath([]);
        } else if (currentPhase === 'pickup-drop') {
            setCurrentPhase('dropping');
            setVehicleState(agvDetail.modelUuid, 'idle');
            setVehiclePicking(agvDetail.modelUuid, false);
            setVehicleActive(agvDetail.modelUuid, false);
            vehicleStatus(agvDetail.modelUuid, 'Reached drop point');
            setPath([]);
        } else if (currentPhase === 'drop-pickup') {
            setCurrentPhase('picking');
            setVehicleState(agvDetail.modelUuid, 'idle');
            setVehiclePicking(agvDetail.modelUuid, true);
            setVehicleActive(agvDetail.modelUuid, false);
            setPath([]);
            clearCurrentMaterials(agvDetail.modelUuid)
            vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete');
        }
    }

    function startUnloadingProcess() {
        if (agvDetail.point.action.triggers.length > 0) {
            const trigger = getTriggerByUuid(selectedProduct.productId, agvDetail.point.action.triggers[0].triggerUuid);
            const model = getEventByModelUuid(selectedProduct.productId, trigger?.triggeredAsset?.triggeredModel?.modelUuid || '');

            if (trigger && model) {
                if (model.type === 'transfer') {
                    const action = getActionByUuid(selectedProduct.productId, agvDetail.point.action.actionUuid);
                    if (action) {
                        handleMaterialDropToConveyor(model);
                    }
                } else if (model.type === 'machine') {
                    // 
                } else if (model.type === 'roboticArm') {
                    const action = getActionByUuid(selectedProduct.productId, agvDetail.point.action.actionUuid);
                    if (action) {
                        handleMaterialDropToArmBot(model);
                    }
                } else if (model.type === 'storageUnit') {
                    const action = getActionByUuid(selectedProduct.productId, agvDetail.point.action.actionUuid);
                    if (action) {
                        handleMaterialDropToStorageUnit(model);
                    }
                }
            } else {
                const droppedMaterial = agvDetail.currentLoad;
                startTime = performance.now();
                handleMaterialDropByDefault(droppedMaterial);
            }
        } else {
            const droppedMaterial = agvDetail.currentLoad;
            startTime = performance.now();
            handleMaterialDropByDefault(droppedMaterial);
        }
    }

    function handleMaterialDropToStorageUnit(model: StorageEventSchema) {
        if (model) {
            if (model.point.action.actionType === 'store') {
                loopMaterialDropToStorage(
                    agvDetail.modelUuid,
                    agvDetail.currentLoad,
                    agvDetail.point.action.unLoadDuration,
                    model.modelUuid,
                    model.point.action.storageCapacity,
                    agvDetail.point.action
                );
            }
        }
    }

    function loopMaterialDropToStorage(
        vehicleId: string,
        vehicleCurrentLoad: number,
        unLoadDuration: number,
        storageUnitId: string,
        storageMaxCapacity: number,
        action: VehicleAction
    ) {
        startTime = performance.now();
        const fixedInterval = ((unLoadDuration / vehicleCurrentLoad) * (1000 / speed));

        const unloadLoop = () => {
            if (isPausedRef.current) {
                pauseTimeRef.current ??= performance.now();
                requestAnimationFrame(unloadLoop);
                return;
            }

            if (pauseTimeRef.current) {
                const pauseDuration = performance.now() - pauseTimeRef.current;
                startTime += pauseDuration;
                pauseTimeRef.current = null;
            }

            const elapsedTime = performance.now() - startTime;
            const storageUnit = getStorageUnitById(storageUnitId);

            if (elapsedTime >= fixedInterval) {
                if (storageUnit && agvDetail &&
                    storageUnit.currentLoad < storageMaxCapacity &&
                    vehicleCurrentLoad > 0) {

                    decrementVehicleLoad(vehicleId, 1);
                    vehicleCurrentLoad -= 1;

                    const material = removeLastMaterial(vehicleId);
                    if (material) {

                        triggerPointActions(action, material.materialId);

                    }

                    if (vehicleCurrentLoad > 0 && storageUnit.currentLoad < storageMaxCapacity) {
                        startTime = performance.now();
                        requestAnimationFrame(unloadLoop);
                    }
                }
            } else {
                requestAnimationFrame(unloadLoop);
            }
        };

        const storageUnit = getStorageUnitById(storageUnitId);
        if (storageUnit && vehicleCurrentLoad > 0 && storageUnit?.currentLoad < storageMaxCapacity) {
            unloadLoop();
        }
    }

    function handleMaterialDropToConveyor(model: ConveyorEventSchema) {
        const conveyor = getConveyorById(model.modelUuid);
        if (conveyor) {
            loopMaterialDropToConveyor(
                agvDetail.modelUuid,
                agvDetail.currentLoad,
                conveyor.modelUuid,
                agvDetail.point.action.unLoadDuration,
                agvDetail.point.action
            );
        }
    }

    function loopMaterialDropToConveyor(
        vehicleId: string,
        vehicleCurrentLoad: number,
        conveyorId: string,
        unLoadDuration: number,
        action: VehicleAction
    ) {
        let lastIncrementTime = performance.now();
        let pauseStartTime: number | null = null;
        let totalPausedDuration = 0;
        const fixedInterval = (unLoadDuration * 1000) / speed;

        const dropLoop = (currentTime: number) => {
            const conveyor = getConveyorById(conveyorId);

            if (isPausedRef.current || (conveyor && conveyor.isPaused)) {
                if (pauseStartTime === null) {
                    pauseStartTime = currentTime;
                }
                requestAnimationFrame(dropLoop);
                return;
            }

            // If we were paused but now resumed
            if (pauseStartTime !== null) {
                totalPausedDuration += currentTime - pauseStartTime;
                pauseStartTime = null;
            }

            // Adjust for paused time
            const adjustedCurrentTime = currentTime - totalPausedDuration;
            const elapsedSinceLastIncrement = adjustedCurrentTime - lastIncrementTime;

            if (elapsedSinceLastIncrement >= fixedInterval) {
                if (conveyor && vehicleCurrentLoad > 0) {
                    decrementVehicleLoad(vehicleId, 1);
                    vehicleCurrentLoad -= 1;

                    const material = removeLastMaterial(vehicleId);
                    if (material) {
                        triggerPointActions(action, material.materialId);
                    }

                    // Update the last increment time (using adjusted time)
                    lastIncrementTime = adjustedCurrentTime;
                }
            }

            // Continue the loop if there's more load to drop
            if (vehicleCurrentLoad > 0) {
                requestAnimationFrame(dropLoop);
            }
        };

        requestAnimationFrame(dropLoop);
    }

    function handleMaterialDropToArmBot(model: RoboticArmEventSchema) {
        const armBot = getArmBotById(model.modelUuid);
        if (armBot && armBot.state === 'idle' && !armBot.isActive) {
            loopMaterialDropToArmBot(
                agvDetail.modelUuid,
                agvDetail.currentLoad,
                agvDetail.point.action.unLoadDuration,
                model.modelUuid,
                agvDetail.point.action
            );
        }
    }

    function loopMaterialDropToArmBot(
        vehicleId: string,
        vehicleCurrentLoad: number,
        unLoadDuration: number,
        armBotId: string,
        action: VehicleAction
    ) {
        startTime = performance.now();
        const armBot = getArmBotById(armBotId);

        if (!armBot || armBot.state !== 'idle' || armBot.isActive || vehicleCurrentLoad <= 0) {
            return;
        }

        const checkIdleDuration = () => {
            if (isPausedRef.current) {
                pauseTimeRef.current ??= performance.now();
                requestAnimationFrame(checkIdleDuration);
                return;
            }

            if (pauseTimeRef.current) {
                const pauseDuration = performance.now() - pauseTimeRef.current;
                startTime += pauseDuration;
                pauseTimeRef.current = null;
            }

            const elapsedTime = performance.now() - startTime;

            if (elapsedTime >= unLoadDuration * (1000 / speed)) {
                const material = getLastMaterial(vehicleId);
                if (material) {
                    vehicleCurrentLoad -= 1;

                    triggerPointActions(action, material.materialId);

                    if (vehicleCurrentLoad > 0) {
                        setTimeout(() => {
                            const waitForNextTransfer = () => {
                                const currentArmBot = getArmBotById(armBotId);
                                if (currentArmBot && currentArmBot.state === 'idle' && !currentArmBot.isActive) {
                                    startTime = performance.now();
                                    loopMaterialDropToArmBot(vehicleId, vehicleCurrentLoad, unLoadDuration, armBotId, action);
                                } else {
                                    requestAnimationFrame(waitForNextTransfer);
                                }
                            };
                            waitForNextTransfer();
                        }, 0)
                    }
                }
            } else {
                requestAnimationFrame(checkIdleDuration);
            }
        };

        checkIdleDuration();
    }

    function handleMaterialDropByDefault(droppedMaterial: number) {
        if (isPausedRef.current) {
            pauseTimeRef.current ??= performance.now();
            requestAnimationFrame(() => handleMaterialDropByDefault(droppedMaterial));
            return;
        }

        if (pauseTimeRef.current) {
            const pauseDuration = performance.now() - pauseTimeRef.current;
            startTime += pauseDuration;
            pauseTimeRef.current = null;
        }

        const elapsedTime = performance.now() - startTime;
        const unLoadDuration = agvDetail.point.action.unLoadDuration;
        fixedInterval = ((unLoadDuration / agvDetail.currentLoad) * (1000 / speed));

        if (elapsedTime >= fixedInterval) {
            let droppedMat = droppedMaterial - 1;
            decrementVehicleLoad(agvDetail.modelUuid, 1);
            const material = removeLastMaterial(agvDetail.modelUuid);
            if (material) {
                setEndTime(material.materialId, performance.now());
                removeMaterial(material.materialId);
            }
            if (droppedMat > 0) {
                startTime = performance.now();
                requestAnimationFrame(() => handleMaterialDropByDefault(droppedMat));
            } else {
                return;
            }
        } else {
            requestAnimationFrame(() => handleMaterialDropByDefault(droppedMaterial));
        }
    }

    return (
        <>
            <VehicleAnimator
                path={path}
                handleCallBack={handleCallBack}
                currentPhase={currentPhase}
                agvUuid={agvDetail?.modelUuid}
                agvDetail={agvDetail}
                reset={reset}
                startUnloadingProcess={startUnloadingProcess}
            />
            <MaterialAnimator agvDetail={agvDetail} />
        </>
    );
}

export default VehicleInstance;