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/store';
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
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';

function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) {
    const { navMesh } = useNavMesh();
    const { isPlaying } = usePlayButtonStore();
    const { removeMaterial } = useMaterialStore();
    const { triggerPointActions } = useTriggerHandler();
    const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = useProductStore();
    const { selectedProduct } = useSelectedProduct();
    const { vehicles, setVehicleActive, setVehicleState, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial } = 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) {
        // console.log(`${modelId} , ${status}`);
    }

    // Function to reset everything
    function reset() {
        setCurrentPhase('stationed');
        setVehicleActive(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');
                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');
                        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');
                    setVehicleActive(agvDetail.modelUuid, true);
                    vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point');
                }
            }
        } else {
            reset()
        }
    }, [vehicles, currentPhase, path, isPlaying]);

    function handleCallBack() {
        if (currentPhase === 'stationed-pickup') {
            setCurrentPhase('picking');
            setVehicleState(agvDetail.modelUuid, 'idle');
            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');
            setVehicleActive(agvDetail.modelUuid, false);
            vehicleStatus(agvDetail.modelUuid, 'Reached drop point');
            setPath([]);
        } else if (currentPhase === 'drop-pickup') {
            setCurrentPhase('picking');
            setVehicleState(agvDetail.modelUuid, 'idle');
            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(action);
                    }
                } else if (model.type === 'machine') {
                    
                } else if (model.type === 'roboticArm') {
                    const action = getActionByUuid(selectedProduct.productId, agvDetail.point.action.actionUuid);
                    if (action) {
                        handleMaterialDropToArmBot(action);
                    }
                } else if (model.type === 'storageUnit') {

                }
            } else {
                const droppedMaterial = agvDetail.currentLoad;
                startTime = performance.now();
                handleMaterialDropByDefault(droppedMaterial);
            }
        } else {
            const droppedMaterial = agvDetail.currentLoad;
            startTime = performance.now();
            handleMaterialDropByDefault(droppedMaterial);
        }
    }

    function handleMaterialDropToConveyor(action: Action) {
        if (agvDetail.currentLoad > 1) {

        } else if (agvDetail.currentLoad === 1 && agvDetail.currentMaterials.length === 1) {
            triggerPointActions(action, agvDetail.currentMaterials[0].materialId);
            decrementVehicleLoad(agvDetail.modelUuid, 1);
            removeLastMaterial(agvDetail.modelUuid);
        }
    }

    function handleMaterialDropToArmBot(action: Action) {
        if (agvDetail.currentLoad > 1) {

        } else if (agvDetail.currentLoad === 1 && agvDetail.currentMaterials.length === 1) {
            triggerPointActions(action, agvDetail.currentMaterials[0].materialId);
        }
    }

    function handleMaterialDropByDefault(droppedMaterial: number) {
        if (isPausedRef.current) {
            if (!pauseTimeRef.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 materialId = removeLastMaterial(agvDetail.modelUuid);
            if (materialId) {
                removeMaterial(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;