'use client';

import React, {
    forwardRef,
    ReactElement,
    useId,
    useImperativeHandle,
    useRef,
    useState,
} from 'react';
import { Ripple } from './ripple';
import { Ripples } from './ripple';
import { RippleAreaProps } from './ripple.types';
import { InteractionEventsType } from './hooks/useRippleEffect';

const TIMEOUT: number = 550;
const rippleAreaContext = React.createContext(false);

const RippleArea = forwardRef(
    ({ central = false, ...props }: RippleAreaProps, ref) => {
        const [ripples, setRipples] = useState<Array<ReactElement>>([]),
            rippleDomain = useRef(null),
            clicked = useRef<boolean>(false),
            uniqueKey = useRef<number>(0),
            uniqueId = useId();

        const classes = props.className
            ? `m3 m3-ripple-domain ${props.className}`.trimEnd()
            : 'm3 m3-ripple-domain';

        const start = (
            event: InteractionEventsType,
            cb: (state: boolean) => void,
        ): void => {
            clicked.current = true;
            cb(clicked.current);

            const rippleDomainChar = rippleDomain.current
                ? rippleDomain.current.getBoundingClientRect()
                : {
                      width: 0,
                      height: 0,
                      left: 0,
                      top: 0,
                  };

            const rippleX: number = !central
                    ? event.clientX - rippleDomainChar.left
                    : rippleDomainChar.width / 2,
                rippleY: number = !central
                    ? event.clientY - rippleDomainChar.top
                    : rippleDomainChar.height / 2,
                rippleSizeX: number =
                    Math.max(
                        Math.abs(rippleDomainChar.width - rippleX),
                        rippleX,
                    ) *
                        2 +
                    2,
                rippleSizeY: number =
                    Math.max(
                        Math.abs(rippleDomainChar.height - rippleY),
                        rippleY,
                    ) *
                        2 +
                    2,
                rippleS: number = (rippleSizeX ** 2 + rippleSizeY ** 2) ** 0.5;

            setRipples((prevRipples: Array<ReactElement>) => {
                if (prevRipples.length === 0) {
                    return [
                        <Ripple
                            key={uniqueKey.current}
                            lifetime={TIMEOUT}
                            rippleS={rippleS}
                            rippleX={rippleX}
                            rippleY={rippleY}
                        />,
                    ];
                }
                const old = [...prevRipples];
                old.push(
                    <Ripple
                        key={uniqueKey.current}
                        lifetime={TIMEOUT}
                        rippleS={rippleS}
                        rippleX={rippleX}
                        rippleY={rippleY}
                    />,
                );
                return old;
            });

            uniqueKey.current += 1;
        };

        const stop = (
            _event: InteractionEventsType,
            cb: (state: boolean) => void,
        ) => {
            clicked.current = false;
            cb(clicked.current);

            setRipples((prevRipples: Array<ReactElement>) => {
                if (prevRipples.length > 0) {
                    const old = [...prevRipples];
                    old.shift();
                    return old;
                }
                return prevRipples;
            });
        };

        useImperativeHandle(
            ref,
            () => ({
                start,
                stop,
            }),
            [start, stop],
        );

        return (
            <span className={classes} id={uniqueId} ref={rippleDomain}>
                <rippleAreaContext.Provider value={clicked.current}>
                    <Ripples>{ripples}</Ripples>
                </rippleAreaContext.Provider>
            </span>
        );
    },
);

export { rippleAreaContext, RippleArea };
