import { useCallback, useState, useEffect, useRef } from "react";
import { useFrame } from "@react-three/fiber";
import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore, useAnimationPlaySpeed } from "../../../../../store/usePlayButtonStore";
import { useSceneContext } from "../../../../scene/sceneContext";
import { useProductContext } from "../../../products/productContext";

export function useRetrieveHandler() {
    const { materialStore, armBotStore, vehicleStore, storageUnitStore, productStore, humanStore, assetStore } = useSceneContext();
    const { selectedProductStore } = useProductContext();
    const { addMaterial } = materialStore();
    const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = productStore();
    const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = storageUnitStore();
    const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = vehicleStore();
    const { getHumanById, incrementHumanLoad, incrementLoadCount, addCurrentMaterial: addCurrentMaterialToHuman } = humanStore();
    const { getAssetById, setCurrentAnimation } = assetStore();
    const { selectedProduct } = selectedProductStore();
    const { getArmBotById, addCurrentAction } = armBotStore();
    const { isPlaying } = usePlayButtonStore();
    const { speed } = useAnimationPlaySpeed();
    const { isPaused } = usePauseButtonStore();
    const { isReset } = useResetButtonStore();

    const [activeRetrievals, setActiveRetrievals] = useState<Map<string, { action: StorageAction, isProcessing: boolean, lastCheckTime: number }>>(new Map());
    const retrievalTimeRef = useRef<Map<string, number>>(new Map());

    const [initialDelayComplete, setInitialDelayComplete] = useState(false);
    const delayTimerRef = useRef<NodeJS.Timeout | null>(null);

    const retrieveLogStatus = (materialUuid: string, status: string) => {
        echo.info(`${materialUuid}, ${status}`);
    }

    const createNewMaterial = useCallback((materialId: string, materialType: string, action: StorageAction) => {
        const modelUuid = getModelUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
        const pointUuid = getPointUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
        if (!modelUuid || !pointUuid) return null;
        const currentTime = performance.now();

        if (action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid &&
            action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid &&
            action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid
        ) {
            const newMaterial: MaterialSchema = {
                materialId: materialId,
                materialName: `${materialType}-${Date.now()}`,
                materialType: materialType,
                isActive: false,
                isVisible: false,
                isPaused: false,
                isRendered: true,
                startTime: currentTime,
                previous: {
                    modelUuid: modelUuid,
                    pointUuid: pointUuid,
                    actionUuid: action.actionUuid
                },
                current: {
                    modelUuid: action.triggers[0]?.triggeredAsset.triggeredModel.modelUuid,
                    pointUuid: action.triggers[0]?.triggeredAsset.triggeredPoint.pointUuid,
                    actionUuid: action.triggers[0]?.triggeredAsset.triggeredAction.actionUuid
                },
            };

            addMaterial(newMaterial);
            return newMaterial;
        }
        return null;
    }, [addMaterial, getModelUuidByActionUuid, getPointUuidByActionUuid, selectedProduct.productUuid]);

    useEffect(() => {
        if (isPlaying && !initialDelayComplete) {
            delayTimerRef.current = setTimeout(() => {
                setInitialDelayComplete(true);
            }, 3000);
        }

        return () => {
            if (delayTimerRef.current) {
                clearTimeout(delayTimerRef.current);
            }
        };
    }, [isPlaying, initialDelayComplete]);

    useEffect(() => {
        if (isReset || isPaused) {
            setInitialDelayComplete(false);
            if (delayTimerRef.current) {
                clearTimeout(delayTimerRef.current);
            }
        }
    }, [isReset, isPaused]);

    useFrame(() => {
        if (!isPlaying || isPaused || isReset || !initialDelayComplete) return;

        const currentTime = performance.now();
        const completedActions: string[] = [];
        let hasChanges = false;

        activeRetrievals.forEach((retrieval, actionUuid) => {
            if (retrieval.isProcessing) return;

            const storageUnit = getStorageUnitById(
                getModelUuidByActionUuid(selectedProduct.productUuid, retrieval.action.actionUuid) ?? ''
            );

            if (!storageUnit || storageUnit.currentLoad <= 0) {
                completedActions.push(actionUuid);
                hasChanges = true;
                return;
            }

            if (retrieval.action.triggers.length === 0 || !retrieval.action.triggers[0]?.triggeredAsset) {
                return;
            }

            const triggeredModel = getEventByModelUuid(
                selectedProduct.productUuid,
                retrieval.action.triggers[0]?.triggeredAsset.triggeredModel.modelUuid
            );

            if (!triggeredModel) return;

            let isIdle = false;

            if (triggeredModel.type === 'roboticArm') {
                const armBot = getArmBotById(triggeredModel.modelUuid);
                isIdle = (armBot && !armBot.isActive && armBot.state === 'idle' && !armBot.currentAction) || false;

                if (!armBot) return;
                if (!retrievalTimeRef.current.has(actionUuid) && isIdle) {
                    retrievalTimeRef.current.set(actionUuid, currentTime);
                    return;
                }

                const idleStartTime = retrievalTimeRef.current.get(actionUuid);
                const minIdleTimeBeforeFirstRetrieval = 5000 / speed;
                const minDelayBetweenRetrievals = 5000 / speed;

                const canProceedFirstRetrieval = idleStartTime !== undefined &&
                    (currentTime - idleStartTime) >= minIdleTimeBeforeFirstRetrieval;

                const lastRetrievalTime = retrievalTimeRef.current.get(`${actionUuid}_last`) ?? null;
                const canProceedSubsequent = lastRetrievalTime === null ||
                    (currentTime - lastRetrievalTime) >= minDelayBetweenRetrievals;

                const canProceed = lastRetrievalTime === null ? canProceedFirstRetrieval : canProceedSubsequent;

                if (isIdle && canProceed) {
                    setActiveRetrievals(prev => {
                        const newRetrievals = new Map(prev);
                        newRetrievals.set(actionUuid, {
                            ...retrieval,
                            isProcessing: true,
                            lastCheckTime: currentTime
                        });
                        return newRetrievals;
                    });

                    const lastMaterial = getLastMaterial(storageUnit.modelUuid);
                    if (lastMaterial) {

                        if (retrieval.action.triggers[0]?.triggeredAsset.triggeredAction?.actionUuid) {
                            const action = getActionByUuid(selectedProduct.productUuid, retrieval.action.triggers[0]?.triggeredAsset.triggeredAction.actionUuid);
                            if (action && action.triggers.length > 0 && action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid) {
                                const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset.triggeredModel.modelUuid);
                                if (model) {
                                    if (model.type === 'vehicle') {
                                        const vehicle = getVehicleById(model.modelUuid);
                                        if (vehicle && !vehicle.isActive && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {

                                            const material = createNewMaterial(
                                                lastMaterial.materialId,
                                                lastMaterial.materialType,
                                                storageUnit.point.action
                                            );
                                            if (material) {

                                                addCurrentAction(
                                                    triggeredModel.modelUuid,
                                                    retrieval.action.triggers[0]?.triggeredAsset.triggeredAction?.actionUuid ?? '',
                                                    material.materialType,
                                                    material.materialId
                                                );
                                                retrieveLogStatus(material.materialName, `is being picked by ${armBot?.modelName}`);
                                            }
                                        }
                                    } else {
                                        const material = createNewMaterial(
                                            lastMaterial.materialId,
                                            lastMaterial.materialType,
                                            storageUnit.point.action
                                        );
                                        if (material) {

                                            addCurrentAction(
                                                triggeredModel.modelUuid,
                                                retrieval.action.triggers[0]?.triggeredAsset.triggeredAction?.actionUuid ?? '',
                                                material.materialType,
                                                material.materialId
                                            );
                                            retrieveLogStatus(material.materialName, `is being picked by ${armBot?.modelName}`);
                                        }
                                    }
                                    setActiveRetrievals(prev => {
                                        const newRetrievals = new Map(prev);
                                        newRetrievals.set(actionUuid, {
                                            ...retrieval,
                                            isProcessing: false,
                                            lastCheckTime: currentTime,
                                        });
                                        return newRetrievals;
                                    });

                                    retrievalTimeRef.current.set(actionUuid, currentTime);

                                }
                            }
                        }

                    }
                } else if (!isIdle) {
                    retrievalTimeRef.current.delete(actionUuid);
                }

            } else if (triggeredModel.type === 'vehicle') {
                const vehicle = getVehicleById(triggeredModel.modelUuid);
                isIdle = (vehicle && !vehicle.isActive && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) || false;

                if (!vehicle) return;

                const loadDuration = vehicle.point.action.unLoadDuration;
                let minDelayBetweenRetrievals = (loadDuration * 1000) / speed;
                const minIdleTimeBeforeFirstRetrieval = 3000 / speed;

                if (!retrievalTimeRef.current.has(actionUuid) && isIdle) {
                    retrievalTimeRef.current.set(actionUuid, currentTime);
                    return;
                }

                const idleStartTime = retrievalTimeRef.current.get(actionUuid);
                const lastRetrievalTime = retrievalTimeRef.current.get(`${actionUuid}_last`) ?? null;

                const canProceedFirstRetrieval = idleStartTime !== undefined &&
                    (currentTime - idleStartTime) >= minIdleTimeBeforeFirstRetrieval;

                const canProceedSubsequent = lastRetrievalTime === null ||
                    (currentTime - lastRetrievalTime) >= minDelayBetweenRetrievals;

                const canProceed = lastRetrievalTime === null ? canProceedFirstRetrieval : canProceedSubsequent;

                if (isIdle && canProceed) {
                    setActiveRetrievals(prev => {
                        const newRetrievals = new Map(prev);
                        newRetrievals.set(actionUuid, {
                            ...retrieval,
                            isProcessing: true,
                            lastCheckTime: currentTime
                        });
                        return newRetrievals;
                    });

                    const lastMaterial = getLastMaterial(storageUnit.modelUuid);
                    if (lastMaterial) {
                        if (vehicle?.currentLoad < vehicle.point.action.loadCapacity) {
                            const material = createNewMaterial(
                                lastMaterial.materialId,
                                lastMaterial.materialType,
                                storageUnit.point.action
                            );

                            if (material) {
                                removeLastMaterial(storageUnit.modelUuid);
                                updateCurrentLoad(storageUnit.modelUuid, -1);
                                incrementVehicleLoad(vehicle.modelUuid, 1);
                                addCurrentMaterial(vehicle.modelUuid, material.materialType, material.materialId);
                                retrieveLogStatus(material.materialName, `is picked by ${vehicle.modelName}`);
                            }
                        }
                    }

                    setActiveRetrievals(prev => {
                        const newRetrievals = new Map(prev);
                        newRetrievals.set(actionUuid, {
                            ...retrieval,
                            isProcessing: false,
                            lastCheckTime: currentTime,
                        });
                        return newRetrievals;
                    });

                    retrievalTimeRef.current.set(actionUuid, currentTime);
                    retrievalTimeRef.current.set(`${actionUuid}_last`, currentTime);
                } else if (!isIdle) {
                    retrievalTimeRef.current.delete(actionUuid);
                    retrievalTimeRef.current.delete(`${actionUuid}_last`);
                }
            } else if (triggeredModel.type === 'human') {
                const human = getHumanById(triggeredModel.modelUuid);
                const humanAsset = getAssetById(triggeredModel.modelUuid);
                const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');

                if (human && !human.isScheduled && human.state === 'idle' && human.currentLoad < (action as HumanAction).loadCapacity) {
                    if (humanAsset && humanAsset.animationState?.current === 'idle') {
                        setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
                    } else if (humanAsset && humanAsset.animationState?.current === 'pickup' && humanAsset.animationState.isCompleted) {
                        const lastMaterial = getLastMaterial(storageUnit.modelUuid);
                        if (lastMaterial) {
                            if (action && human.currentLoad < (action as HumanAction).loadCapacity) {
                                const material = createNewMaterial(
                                    lastMaterial.materialId,
                                    lastMaterial.materialType,
                                    storageUnit.point.action
                                );
                                if (material) {
                                    removeLastMaterial(storageUnit.modelUuid);
                                    updateCurrentLoad(storageUnit.modelUuid, -1);
                                    incrementHumanLoad(human.modelUuid, 1);
                                    incrementLoadCount(human.modelUuid, 1);
                                    addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId);
                                    retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`);
                                }
                                if (human.currentLoad + 1 < (action as HumanAction).loadCapacity) {
                                }
                            }
                        }
                    }
                }
            }
        });

        if (hasChanges || completedActions.length > 0) {
            setActiveRetrievals(prev => {
                const newRetrievals = new Map(prev);
                completedActions.forEach(actionUuid => newRetrievals.delete(actionUuid));
                return newRetrievals;
            });
        }
    });

    const handleRetrieve = useCallback((action: StorageAction) => {
        if (!action || action.actionType !== 'retrieve') return;

        setActiveRetrievals(prev => {
            const newRetrievals = new Map(prev);
            newRetrievals.set(action.actionUuid, {
                action,
                isProcessing: false,
                lastCheckTime: performance.now(),
            });
            return newRetrievals;
        });
    }, []);

    useEffect(() => {
        if (isReset) {
            setActiveRetrievals(new Map());
            setInitialDelayComplete(false);
        }
    }, [isReset]);

    return {
        handleRetrieve,
    };
}