import { IPalmistryFinger, IPalmistryLine } from '@/api/resources/Palmistry';
import { useState, useEffect, useCallback, useRef } from 'react';
import { getShuffledHands } from './hands';

const hands = getShuffledHands();

export interface DisplayHand {
    image: string;
    willBeRemoved: boolean;
    id: number;
    lines: IPalmistryLine[];
    fingers: IPalmistryFinger[];
}

interface HandsToDelete {
    hands: DisplayHand[];
    deleteAt: number;
    markAt: number;
    marked: boolean;
}

export const useHandsGeneration = () => {
    const [displayHands, setDisplayHands] = useState<DisplayHand[]>([]);
    const [handsToDeleteQueue, setHandsToDeleteQueue] = useState<HandsToDelete[]>([]);
    const currentHandIndexRef = useRef(1);

    const minHands = 1;
    const maxHands = 5;

    const getHand = useCallback(() => {
        const currentIndex = currentHandIndexRef.current;

        currentHandIndexRef.current = currentIndex >= hands.length ? 1 : currentIndex + 1;

        const currentHand = hands[currentIndex - 1];

        return {
            id: Date.now() + Math.random(),
            image: currentHand.image,
            willBeRemoved: false,
            lines: currentHand.lines,
            fingers: currentHand.fingers
        }
    }, []);

    const createHand = useCallback(() => {
        return getHand();
    }, [getHand]);

    useEffect(() => {
        addHands(3);
        return () => setDisplayHands([]);
    }, []);

    const addHands = useCallback((countHands?: number) => {
        const addHandsTimeout = 6000 + Math.random() * 4000;

        const count = !!countHands ? countHands : Math.random() < 0.6 ? 1 : 2;
        const _newHands = Array(count).fill(null).map(createHand);

        setDisplayHands(prev => {
            const updatedHands = [...prev, ..._newHands].slice(-maxHands);

            if (updatedHands.length < minHands) {
                const additionalCount = minHands - updatedHands.length;
                const additionalHands = Array(additionalCount).fill(null).map(createHand);
                return [...updatedHands, ...additionalHands];
            }

            return updatedHands;
        });

        const now = Date.now();
        setHandsToDeleteQueue(prev => [...prev, ..._newHands.map((value) => {
            const deleteTime = 6000 + Math.random() * 20000;
            return {
                hands: [value],
                deleteAt: now + deleteTime,
                markAt: now + deleteTime - 3000,
                marked: false
            }
        })]);

        const timeoutAddHands = setTimeout(() => {
            addHands();
            clearTimeout(timeoutAddHands);
        }, addHandsTimeout);
    }, [createHand]);

    useEffect(() => {
        if (handsToDeleteQueue.length === 0) return;

        const checkQueue = () => {
            const now = Date.now();

            setHandsToDeleteQueue(prev => {
                const updatedQueue = [...prev];
                let hasChanges = false;

                updatedQueue.forEach(item => {
                    if (displayHands.length <= minHands) return;
                    if (!item.marked && now >= item.markAt) {
                        markHands(item.hands);
                        item.marked = true;
                        hasChanges = true;
                    }
                    if (now >= item.deleteAt) {
                        deleteHands(item.hands);
                        hasChanges = true;
                    }
                });

                return hasChanges ? updatedQueue.filter(item => now < item.deleteAt) : updatedQueue;
            });
        };

        const interval = setInterval(checkQueue, 100);
        return () => clearInterval(interval);
    }, [handsToDeleteQueue]);

    const deleteHands = (handsToDelete: DisplayHand[]) => {
        setDisplayHands(prev =>
            prev.filter(hand => !handsToDelete.some(h => h.id === hand.id))
        );
    }

    const markHands = (handsToMark: DisplayHand[]) => {
        setDisplayHands(prev =>
            prev.map(hand =>
                handsToMark.some(h => h.id === hand.id)
                    ? { ...hand, willBeRemoved: true }
                    : hand
            )
        );
    }

    return { displayHands };
};