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

type ConveyorCallback = {
    conveyorId: string;
    callback: () => void;
    except: string[];
};

export function useConveyorEventManager() {
    const { materialStore } = useSceneContext();
    const { getMaterialsByCurrentModelUuid } = materialStore();
    const callbacksRef = useRef<Map<string, ConveyorCallback[]>>(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();
            isCooldownRef.current.clear();
            isMonitoringRef.current = false;
        }
    }, [isReset]);

    const addConveyorToMonitor = (conveyorId: string, callback: () => void, except?: string[]) => {
        if (!callbacksRef.current.has(conveyorId)) {
            callbacksRef.current.set(conveyorId, []);
        }

        callbacksRef.current.get(conveyorId)!.push({ conveyorId, callback, except: except || [] });
        isMonitoringRef.current = true;
    };

    const removeConveyorFromMonitor = (conveyorId: string) => {
        callbacksRef.current.delete(conveyorId);
        isCooldownRef.current.delete(conveyorId);
        if (callbacksRef.current.size === 0) {
            isMonitoringRef.current = false;
        }
    };

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

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

            const { callback, except } = queue[0];
            const conveyorMaterials = getMaterialsByCurrentModelUuid(conveyorId);

            let conditionMet = false;

            if (!conveyorMaterials || conveyorMaterials.length === 0) {
                conditionMet = true;
            } else {
                const pausedMaterials = conveyorMaterials.filter(m => m.isPaused);

                if (pausedMaterials.length === 0) {
                    conditionMet = true;
                } else {
                    const allPausedInExcept = pausedMaterials.filter(m => !except.includes(m.materialId));
                    if (allPausedInExcept.length === 0) {
                        conditionMet = true;
                    }
                }
            }

            if (conditionMet) {
                queue.shift();
                if (callback) callback();

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

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

    return {
        addConveyorToMonitor,
        removeConveyorFromMonitor,
    };
}
