import React, {
    DetailedHTMLProps,
    HTMLAttributes,
    PropsWithChildren,
} from "react";
import { twMerge } from "tailwind-merge";

export const TWUIDropdownContentPositions = [
    "left",
    "bottom-left",
    "top-left",
    "right",
    "bottom-right",
    "top-right",
    "center",
] as const;

export type TWUI_DROPDOWN_PROPS = PropsWithChildren &
    DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement> & {
        target: React.ReactNode;
        contentWrapperProps?: DetailedHTMLProps<
            HTMLAttributes<HTMLDivElement>,
            HTMLDivElement
        >;
        targetWrapperProps?: DetailedHTMLProps<
            HTMLAttributes<HTMLDivElement>,
            HTMLDivElement
        >;
        debounce?: number;
        openDebounce?: number;
        hoverOpen?: boolean;
        above?: boolean;
        position?: (typeof TWUIDropdownContentPositions)[number];
        topOffset?: number;
        externalSetOpen?: React.Dispatch<React.SetStateAction<boolean>>;
        externalOpen?: boolean;
        keepOpen?: boolean;
        disableClickActions?: boolean;
    };

/**
 * # Toggle Component
 * @className_wrapper twui-dropdown-wrapper
 * @className_wrapper twui-dropdown-target
 * @className_wrapper twui-dropdown-content
 *
 * @note use the class `cancel-link` to prevent popup open on click
 */
export default function Dropdown({
    contentWrapperProps,
    targetWrapperProps,
    hoverOpen,
    above,
    debounce = 200,
    openDebounce = 200,
    target,
    position = "center",
    topOffset,
    externalSetOpen,
    keepOpen,
    disableClickActions,
    externalOpen,
    ...props
}: TWUI_DROPDOWN_PROPS) {
    const [open, setOpen] = React.useState(externalOpen);

    let timeout: any;
    let openTimeout: any;

    const dropdownRef = React.useRef<HTMLDivElement>(null);
    const dropdownContentRef = React.useRef<HTMLDivElement>(null);

    const handleClickOutside = React.useCallback((e: MouseEvent) => {
        const targetEl = e.target as HTMLElement;
        const closestWrapper = targetEl.closest(".twui-dropdown-wrapper");

        if (!closestWrapper) {
            externalSetOpen?.(false);
            return setOpen(false);
        }
        if (closestWrapper && closestWrapper !== dropdownRef.current) {
            externalSetOpen?.(false);
            return setOpen(false);
        }
    }, []);

    React.useEffect(() => {
        if (keepOpen) return;
        document.addEventListener("click", handleClickOutside);
        return () => {
            document.removeEventListener("click", handleClickOutside);
        };
    }, []);

    React.useEffect(() => {
        setOpen(externalOpen);
    }, [externalOpen]);

    return (
        <div
            {...props}
            className={twMerge(
                "flex flex-col items-center relative",
                "twui-dropdown-wrapper",
                props.className
            )}
            onMouseEnter={() => {
                if (!hoverOpen) return;
                window.clearTimeout(timeout);
                window.clearTimeout(openTimeout);

                openTimeout = setTimeout(() => {
                    externalSetOpen?.(true);
                    setOpen(true);
                }, openDebounce);
            }}
            onMouseLeave={(e) => {
                if (!hoverOpen) return;

                window.clearTimeout(openTimeout);

                timeout = setTimeout(() => {
                    externalSetOpen?.(false);
                    setOpen(false);
                }, debounce);
            }}
            onBlur={() => {
                window.clearTimeout(timeout);
            }}
            ref={dropdownRef}
        >
            <div
                onClick={(e) => {
                    const targetEl = e.target as HTMLElement | null;
                    if (targetEl?.closest?.(".cancel-link")) return;
                    if (disableClickActions) return;
                    externalSetOpen?.(!open);
                    setOpen(!open);
                }}
                className={twMerge(
                    "cursor-pointer",
                    "twui-dropdown-target",
                    targetWrapperProps?.className
                )}
            >
                {target}
            </div>

            <div
                {...contentWrapperProps}
                className={twMerge(
                    "absolute z-10 mt-1",
                    position == "left"
                        ? "left-[100%] top-[50%] -translate-y-[50%]"
                        : position == "right"
                        ? "right-[100%] top-[50%] -translate-y-[50%]"
                        : position == "bottom-left"
                        ? "left-0 top-[100%]"
                        : position == "bottom-right"
                        ? "right-0 top-[100%]"
                        : position == "center"
                        ? "left-[50%] -translate-x-[50%] top-[100%]"
                        : "top-[100%]",
                    above ? "-translate-y-[120%]" : "",
                    open ? "flex" : "hidden",
                    "twui-dropdown-content",
                    contentWrapperProps?.className
                )}
                onMouseEnter={() => {
                    if (!hoverOpen) return;
                    window.clearTimeout(timeout);
                }}
                onBlur={() => {
                    if (!hoverOpen) return;
                    window.clearTimeout(timeout);
                }}
                style={{
                    // top: `calc(100% + ${topOffset || 0}px)`,
                    ...contentWrapperProps?.style,
                }}
                ref={dropdownContentRef}
            >
                {props.children}
            </div>
        </div>
    );
}
