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";
import { useHumanEventManager } from "../../../human/eventManager/useHumanEventManager";

export function useRetrieveHandler() {
    const { materialStore, armBotStore, machineStore, vehicleStore, storageUnitStore, conveyorStore, craneStore, productStore, humanStore, assetStore, humanEventManagerRef } = 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 { getConveyorById } = conveyorStore();
    const { getHumanById, incrementHumanLoad, addCurrentMaterial: addCurrentMaterialToHuman } = humanStore();
    const { getCraneById, incrementCraneLoad, addCurrentMaterial: addCurrentMaterialToCrane, addCurrentAction: addCurrentActionToCrane } = craneStore();
    const { getAssetById, setCurrentAnimation } = assetStore();
    const { selectedProduct } = selectedProductStore();
    const { getArmBotById, addCurrentAction } = armBotStore();
    const { getMachineById } = machineStore();
    const { isPlaying } = usePlayButtonStore();
    const { speed } = useAnimationPlaySpeed();
    const { isPaused } = usePauseButtonStore();
    const { isReset } = useResetButtonStore();
    const { addHumanToMonitor } = useHumanEventManager();

    const [activeRetrievals, setActiveRetrievals] = useState<Map<string, { action: StorageAction, isProcessing: boolean, lastCheckTime: number }>>(new Map());
    const retrievalTimeRef = useRef<Map<string, number>>(new Map());
    const retrievalCountRef = useRef<Map<string, number>>(new Map());
    const monitoredHumansRef = useRef<Set<string>>(new Set());
    const cranePickupLockRef = useRef<Map<string, boolean>>(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, visible: boolean = false) => {
        const modelUuid = getModelUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
        const pointUuid = getPointUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
        if (!modelUuid || !pointUuid) return null;
        const currentTime = performance.now();

        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: modelUuid,
                pointUuid: pointUuid,
                actionUuid: action.actionUuid
            },
        };

        addMaterial(newMaterial);
        return newMaterial;
    }, [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) {
                completedActions.push(actionUuid);
                hasChanges = true;
                return;
            }

            if (storageUnit.currentLoad <= 0) {
                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);
                            const storageAction = getActionByUuid(selectedProduct.productUuid, 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 && storageAction) {
                                    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,
                                                storageAction as StorageAction
                                            );
                                            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 if (storageAction) {
                                        const material = createNewMaterial(
                                            lastMaterial.materialId,
                                            lastMaterial.materialType,
                                            storageAction as StorageAction
                                        );
                                        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 triggeredAction = getActionByUuid(
                                selectedProduct.productUuid,
                                retrieval.action.triggers[0]?.triggeredAsset.triggeredAction?.actionUuid || ''
                            );

                            const material = createNewMaterial(
                                lastMaterial.materialId,
                                lastMaterial.materialType,
                                triggeredAction as StorageAction
                            );

                            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 (!action || action.actionType !== 'worker') return;

                const currentCount = retrievalCountRef.current.get(actionUuid) ?? 0;

                if (currentCount >= action.loadCount) {
                    completedActions.push(actionUuid);
                    hasChanges = true;
                    return;
                }

                if (human && !human.isScheduled && human.state === 'idle' && human.currentLoad < action.loadCapacity) {
                    const triggeredModel = action.triggers[0]?.triggeredAsset?.triggeredModel?.modelUuid
                        ? getEventByModelUuid(selectedProduct.productUuid, action.triggers[0].triggeredAsset.triggeredModel.modelUuid)
                        : null;

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

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

                                        retrievalCountRef.current.set(actionUuid, currentCount + 1);
                                    }
                                }
                            }
                            return;
                        }
                    } else if (triggeredModel?.type === 'roboticArm') {
                        const armBot = getArmBotById(triggeredModel.modelUuid);
                        if (armBot && !armBot.isActive && armBot.state === 'idle' && !armBot.currentAction) {
                            if (humanAsset?.animationState?.current === 'idle') {
                                setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
                            } else if (humanAsset?.animationState?.current === 'pickup' && humanAsset.animationState.isCompleted) {
                                const lastMaterial = getLastMaterial(storageUnit.modelUuid);
                                if (lastMaterial) {
                                    const material = createNewMaterial(
                                        lastMaterial.materialId,
                                        lastMaterial.materialType,
                                        storageAction as StorageAction
                                    );
                                    if (material) {
                                        removeLastMaterial(storageUnit.modelUuid);
                                        updateCurrentLoad(storageUnit.modelUuid, -1);
                                        incrementHumanLoad(human.modelUuid, 1);
                                        addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId);
                                        retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`);

                                        retrievalCountRef.current.set(actionUuid, currentCount + 1);
                                    }
                                }
                            }
                            return;
                        }
                    } else if (triggeredModel?.type === 'transfer') {
                        const model = getConveyorById(triggeredModel.modelUuid);
                        if (model && !model.isPaused) {
                            if (humanAsset?.animationState?.current === 'idle') {
                                setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
                            } else if (humanAsset?.animationState?.current === 'pickup' && humanAsset.animationState.isCompleted) {
                                const lastMaterial = getLastMaterial(storageUnit.modelUuid);
                                if (lastMaterial) {
                                    const material = createNewMaterial(
                                        lastMaterial.materialId,
                                        lastMaterial.materialType,
                                        storageAction as StorageAction
                                    );
                                    if (material) {
                                        removeLastMaterial(storageUnit.modelUuid);
                                        updateCurrentLoad(storageUnit.modelUuid, -1);
                                        incrementHumanLoad(human.modelUuid, 1);
                                        addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId);
                                        retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`);

                                        retrievalCountRef.current.set(actionUuid, currentCount + 1);
                                    }
                                }
                            }
                            return;
                        }
                    } else if (triggeredModel?.type === 'machine') {
                        const machine = getMachineById(triggeredModel.modelUuid);
                        if (machine && !machine.isActive && machine.state === 'idle' && !machine.currentAction) {
                            if (!monitoredHumansRef.current.has(human.modelUuid)) {
                                addHumanToMonitor(human.modelUuid, () => {
                                    if (humanAsset?.animationState?.current === 'idle') {
                                        setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
                                    }
                                }, action.actionUuid);
                            }
                            monitoredHumansRef.current.add(human.modelUuid);
                            if (humanAsset?.animationState?.current === 'pickup' && humanAsset.animationState.isCompleted) {
                                const lastMaterial = getLastMaterial(storageUnit.modelUuid);
                                if (lastMaterial) {
                                    const material = createNewMaterial(
                                        lastMaterial.materialId,
                                        lastMaterial.materialType,
                                        storageAction as StorageAction
                                    );
                                    if (material) {
                                        removeLastMaterial(storageUnit.modelUuid);
                                        updateCurrentLoad(storageUnit.modelUuid, -1);
                                        incrementHumanLoad(human.modelUuid, 1);
                                        addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId);
                                        retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`);
                                        retrievalCountRef.current.set(actionUuid, currentCount + 1);
                                    }
                                }
                                monitoredHumansRef.current.delete(human.modelUuid);
                            }
                            return;
                        }
                    } else if (triggeredModel?.type === 'storageUnit') {
                        const lastMaterial = getLastMaterial(storageUnit.modelUuid);
                        if (lastMaterial) {
                            const material = createNewMaterial(
                                lastMaterial.materialId,
                                lastMaterial.materialType,
                                storageAction as StorageAction
                            );
                            if (material) {
                                removeLastMaterial(storageUnit.modelUuid);
                                updateCurrentLoad(storageUnit.modelUuid, -1);
                                incrementHumanLoad(human.modelUuid, 1);
                                addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId);
                                retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`);

                                retrievalCountRef.current.set(actionUuid, currentCount + 1);
                            }
                        }
                    }
                }
            } else if (triggeredModel?.type === 'crane') {
                const crane = getCraneById(triggeredModel.modelUuid);
                const action = getActionByUuid(selectedProduct.productUuid, crane?.currentAction?.actionUuid || '');
                const currentCount = retrievalCountRef.current.get(actionUuid) ?? 0;

                if (!crane) return;

                const hasLock = cranePickupLockRef.current.get(crane.modelUuid) || false;

                if (action && action.actionType === 'pickAndDrop' && !hasLock && !crane.isCarrying && !crane.isActive && crane.currentLoad < (action?.maxPickUpCount || 0)) {
                    const material = getLastMaterial(storageUnit.modelUuid);
                    if (material) {
                        if (action.triggers[0].triggeredAsset?.triggeredModel.modelUuid && action.triggers[0].triggeredAsset.triggeredAction?.actionUuid) {
                            const human = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0].triggeredAsset.triggeredModel.modelUuid);
                            if (human && human.type === 'human') {
                                if (!monitoredHumansRef.current.has(human.modelUuid)) {
                                    addHumanToMonitor(human.modelUuid, () => {
                                        incrementCraneLoad(crane.modelUuid, 1);
                                        addCurrentActionToCrane(crane.modelUuid, action.actionUuid, material.materialType, material.materialId);
                                        addCurrentMaterialToCrane(crane.modelUuid, material.materialType, material.materialId);
                                        cranePickupLockRef.current.set(crane.modelUuid, true);
                                        monitoredHumansRef.current.delete(human.modelUuid);
                                    }, action.triggers[0].triggeredAsset.triggeredAction?.actionUuid)
                                }
                                monitoredHumansRef.current.add(human.modelUuid);
                            }
                        }
                    }
                } else if (crane.isCarrying && crane.currentPhase === 'pickup-drop' && hasLock) {
                    cranePickupLockRef.current.set(crane.modelUuid, false);

                    const lastMaterial = getLastMaterial(storageUnit.modelUuid);
                    if (lastMaterial) {
                        const triggeredAction = getActionByUuid(
                            selectedProduct.productUuid,
                            action?.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid || ''
                        );

                        const material = createNewMaterial(
                            lastMaterial.materialId,
                            lastMaterial.materialType,
                            triggeredAction as StorageAction
                        );
                        if (material) {
                            removeLastMaterial(storageUnit.modelUuid);
                            updateCurrentLoad(storageUnit.modelUuid, -1);
                            retrievalCountRef.current.set(actionUuid, currentCount + 1);
                        }
                    }
                } else if (!action) {
                    const action = getActionByUuid(selectedProduct.productUuid, retrieval.action.triggers[0]?.triggeredAsset.triggeredAction?.actionUuid || '');
                    if (action) {
                        addCurrentActionToCrane(crane.modelUuid, action.actionUuid, null, null);
                    }
                }
            }

        });

        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 || !isPlaying) {
            setActiveRetrievals(new Map());
            retrievalCountRef.current.clear();
            setInitialDelayComplete(false);
        }
    }, [isReset, isPlaying]);

    return {
        handleRetrieve,
    };
}