import React, {
    ForwardedRef,
    MutableRefObject,
    useCallback,
    useImperativeHandle,
    useRef,
    useState,
    useTransition,
} from 'react';
import { Ripple } from '../ripple';
import { baseDOMRect, RippleContainer } from '../ripple.types';
import isEmpty, { rippleSizeCalculator } from '../utils/utils';
import { InteractionEventsType } from './useRippleEffect';

const RIPPLE_LIFETIME: number = 550;
const DEBOUNCE: number = 50;

const UseRippleBuilder = (
    stateRef: MutableRefObject<boolean>,
    rippleDomainRef: MutableRefObject<HTMLSpanElement>,
    central: boolean,
    forwardedRef: ForwardedRef<RippleContainer>,
) => {
    const [ripples, setRipples] = useState({});
    const [pending, transition] = useTransition();
    const debounced = useRef<boolean>(false);
    const uniqueKey = useRef<number>(0);

    const endLifetimeRipple = (keyRipple: number) => {
        if (!pending && !isEmpty(ripples)) {
            transition(() => {
                setRipples(prevRipples => {
                    delete prevRipples[keyRipple];
                    return prevRipples;
                });
            });
        }
    };

    const createRipple = useCallback(
        (
            event: InteractionEventsType,
            changeStateCallback: (state: boolean) => void,
        ): void => {
            if (stateRef.current || debounced.current) {
                return;
            }

            debounced.current = true;

            setTimeout(() => {
                debounced.current = false;
            }, DEBOUNCE);

            stateRef.current = true;
            changeStateCallback(stateRef.current);

            const rippleDomain: DOMRect | baseDOMRect = rippleDomainRef.current
                ? rippleDomainRef.current.getBoundingClientRect()
                : {
                      width: 0,
                      height: 0,
                      left: 0,
                      top: 0,
                  };

            const [rippleX, rippleY, rippleS]: Array<number> =
                rippleSizeCalculator(event, rippleDomain, central);

            const prevRipples = ripples;

            prevRipples[uniqueKey.current] = (
                <Ripple
                    endLifetime={endLifetimeRipple}
                    key={uniqueKey.current}
                    lifetime={RIPPLE_LIFETIME}
                    rippleKey={uniqueKey.current}
                    rippleS={rippleS}
                    rippleX={rippleX}
                    rippleY={rippleY}
                />
            );

            setRipples(prevRipples);

            uniqueKey.current += 1;
        },
        [uniqueKey, debounced],
    );

    const removeRipple = (
        event: InteractionEventsType,
        changeStateCallback: (state: boolean) => void,
    ) => {
        if (!stateRef.current) {
            return;
        }
        stateRef.current = false;
        changeStateCallback(stateRef.current);
    };

    useImperativeHandle(
        forwardedRef,
        () => ({
            start: createRipple,
            stop: removeRipple,
            current: rippleDomainRef,
        }),
        [createRipple, removeRipple],
    );

    return ripples;
};

export default UseRippleBuilder;
