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

export function useHumanEventManager() {
    const { humanStore, productStore, assetStore } = useSceneContext();
    const { getHumanById, clearLoadCount, setCurrentPhase } = humanStore();
    const { getAssetById } = assetStore();
    const { getActionByUuid } = productStore();
    const { selectedProductStore } = useProductContext();
    const { selectedProduct } = selectedProductStore();

    const callbacksRef = useRef<Map<string, (() => void)[]>>(new Map());
    const actionQueueRef = useRef<Map<string, { actionType: "worker" | "assembly", actionUuid: string }[]>>(new Map());
    const isCooldownRef = useRef<Map<string, boolean>>(new Map());
    const isMonitoringRef = useRef(false);

    const { isPlaying } = usePlayButtonStore();
    const { isPaused } = usePauseButtonStore();
    const { isReset } = useResetButtonStore();

    useEffect(() => {
        if (isReset) {
            callbacksRef.current.clear();
            actionQueueRef.current.clear();
            isCooldownRef.current.clear();
            isMonitoringRef.current = false;
        }
    }, [isReset]);

    const addHumanToMonitor = (humanId: string, callback: () => void, actionUuid: string) => {
        const action = getActionByUuid(selectedProduct.productUuid, actionUuid || '') as HumanAction | undefined;

        if (!action) return;

        const actionType = action.actionType;
        if (actionType !== "worker" && actionType !== "assembly") return;

        if (!callbacksRef.current.has(humanId)) {
            callbacksRef.current.set(humanId, []);
            actionQueueRef.current.set(humanId, []);
        }

        callbacksRef.current.get(humanId)!.push(callback);
        actionQueueRef.current.get(humanId)!.push({ actionType, actionUuid });

        isMonitoringRef.current = true;
    };

    const removeHumanFromMonitor = (humanId: string) => {
        callbacksRef.current.delete(humanId);
        actionQueueRef.current.delete(humanId);
        isCooldownRef.current.delete(humanId);

        if (callbacksRef.current.size === 0) {
            isMonitoringRef.current = false;
        }
    };

    useFrame(() => {
        if (!isMonitoringRef.current || !isPlaying || isPaused) return;

        callbacksRef.current.forEach((queue, humanId) => {
            if (queue.length === 0 || isCooldownRef.current.get(humanId)) return;

            const actionQueue = actionQueueRef.current.get(humanId);
            if (!actionQueue || actionQueue.length === 0) return;

            const { actionType: expectedActionType, actionUuid } = actionQueue[0];
            const human = getHumanById(humanId);
            const humanAsset = getAssetById(humanId);
            const action = getActionByUuid(selectedProduct.productUuid, actionUuid) as HumanAction | undefined;

            if (!humanAsset || !human || !action || action.actionType !== expectedActionType) return;

            let conditionMet = false;

            const currentAction = getActionByUuid(selectedProduct.productUuid, human.currentAction?.actionUuid || '') as HumanAction | undefined;

            if (expectedActionType === "worker") {
                if (currentAction && currentAction.actionType === 'worker') {
                    conditionMet = (
                        !human.isActive &&
                        human.state === "idle" &&
                        humanAsset.animationState?.current === 'idle' &&
                        human.currentLoad < currentAction.loadCapacity
                    );

                    if (human.totalLoadCount >= currentAction.loadCount && actionUuid === human.currentAction?.actionUuid) {
                        queue.shift();
                        actionQueue.shift();
                        if (queue.length === 0) {
                            removeHumanFromMonitor(humanId);
                        }
                        return;
                    }

                    if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
                        setCurrentPhase(human.modelUuid, 'init');
                    }
                } else {
                    conditionMet = (
                        !human.isActive &&
                        human.state === "idle" &&
                        humanAsset.animationState?.current === 'idle' &&
                        human.currentLoad < action.loadCapacity
                    );
                    if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
                        setCurrentPhase(human.modelUuid, 'init');
                    }
                }

            } else if (expectedActionType === "assembly") {
                if (currentAction && currentAction.actionType === 'worker') {
                    conditionMet = (
                        !human.isActive &&
                        human.state === "idle" &&
                        humanAsset.animationState?.current === 'idle' &&
                        human.currentLoad < currentAction.loadCapacity
                    );
                    if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
                        setCurrentPhase(human.modelUuid, 'init');
                    }
                } else {
                    conditionMet = (
                        !human.isActive &&
                        human.state === "idle" &&
                        humanAsset.animationState?.current === 'idle' &&
                        human.currentLoad < action.loadCapacity
                    )
                }
                if (conditionMet) {
                    clearLoadCount(human.modelUuid);
                }
            }

            if (conditionMet) {
                const callback = queue.shift();
                actionQueue.shift();

                if (callback) callback();

                if (queue.length === 0) {
                    removeHumanFromMonitor(humanId);
                } else {
                    isCooldownRef.current.set(humanId, true);
                    setTimeout(() => {
                        isCooldownRef.current.set(humanId, false);
                    }, 1000);
                }
            }
        });
    }, 0);

    useEffect(() => {
        return () => {
            callbacksRef.current.clear();
            actionQueueRef.current.clear();
            isCooldownRef.current.clear();
            isMonitoringRef.current = false;
        };
    }, []);

    return {
        addHumanToMonitor,
        removeHumanFromMonitor,
    };
}
