import { useState, useEffect, useRef, useCallback } from 'react';
import { playTimeUpSignal } from '../utils/audio';

export type TimerStatus = 'IDLE' | 'RUNNING' | 'PAUSED' | 'FINISHED';

interface UseRestTimerProps {
    defaultTime: number; // in seconds
    onFinish?: () => void;
    autoStart?: boolean;
}

export const useRestTimer = ({ defaultTime, onFinish }: UseRestTimerProps) => {
    const [timeLeft, setTimeLeft] = useState(defaultTime);
    const [status, setStatus] = useState<TimerStatus>('IDLE');
    const [duration, setDuration] = useState(defaultTime); // The set duration to reset to

    const endTimeRef = useRef<number | null>(null);
    const rafRef = useRef<number | null>(null);
    const prevDefaultTimeRef = useRef(defaultTime);

    // Update internal duration when defaultTime changes
    useEffect(() => {
        if (prevDefaultTimeRef.current !== defaultTime) {
            prevDefaultTimeRef.current = defaultTime;
            setDuration(defaultTime);
            // Only update visible time if IDLE. If running, it will apply on next reset.
            if (status === 'IDLE') {
                setTimeLeft(defaultTime);
            }
        }
    }, [defaultTime, status]);

    useEffect(() => {
        return () => {
            if (rafRef.current) cancelAnimationFrame(rafRef.current);
        };
    }, []);

    const tick = useCallback(() => {
        if (!endTimeRef.current) return;
        const now = Date.now();
        const remaining = Math.max(0, Math.ceil((endTimeRef.current - now) / 1000));

        setTimeLeft(remaining);

        if (remaining <= 0) {
            setStatus('FINISHED');
            playTimeUpSignal();
            if (onFinish) onFinish();

            // Auto-reset visuals after 3 seconds of "FINISHED" state?
            // Requirement says: "The FAB must first change color to red for 3 seconds, and then return to the idle state"
            // So the hook stays in FINISHED.
            setTimeout(() => {
                reset();
            }, 3000);
        } else {
            rafRef.current = requestAnimationFrame(tick);
        }
    }, [onFinish]);

    const start = useCallback(() => {
        if (status === 'RUNNING') return;

        // If starting from IDLE or PAUSED
        const targetSeconds = status === 'PAUSED' ? timeLeft : duration;
        endTimeRef.current = Date.now() + targetSeconds * 1000;

        setStatus('RUNNING');
        rafRef.current = requestAnimationFrame(tick);
    }, [status, timeLeft, duration, tick]);

    const pause = useCallback(() => {
        if (status !== 'RUNNING') return;
        setStatus('PAUSED');
        if (rafRef.current) cancelAnimationFrame(rafRef.current);
        endTimeRef.current = null;
    }, [status]);

    const reset = useCallback((newDuration?: number) => {
        if (rafRef.current) cancelAnimationFrame(rafRef.current);

        const nextDuration = newDuration !== undefined ? newDuration : duration;
        setDuration(nextDuration);
        setTimeLeft(nextDuration);
        setStatus('IDLE');
        endTimeRef.current = null;
    }, [duration]);

    const addTime = useCallback((seconds: number) => {
        setDuration(prev => prev + seconds);
        if (status === 'IDLE') {
            setTimeLeft(prev => prev + seconds);
        } else if (status === 'RUNNING') {
            // Add to current target
            if (endTimeRef.current) {
                endTimeRef.current += seconds * 1000;
                // Force immediate update to avoid flicker
                const now = Date.now();
                setTimeLeft(Math.max(0, Math.ceil((endTimeRef.current - now) / 1000)));
            }
        } else if (status === 'PAUSED') {
            setTimeLeft(prev => prev + seconds);
        }
    }, [status]);


    return {
        timeLeft,
        status,
        start,
        pause,
        reset,
        addTime,
        setDuration: (val: number) => {
            setDuration(val);
            if (status === 'IDLE') setTimeLeft(val);
        }
    };
};
