import React, { DetailedHTMLProps, HTMLAttributes } from "react";
import ModalComponent from "../(partials)/ModalComponent";
import PopoverComponent from "../(partials)/PopoverComponent";
import { twMerge } from "tailwind-merge";

export const TWUIPopoverStyles = [
    "top",
    "bottom",
    "left",
    "right",
    "transform",
    "bottom-left",
    "bottom-right",
] as const;
export const TWUIPopoverTriggers = ["hover", "click"] as const;

export type TWUI_MODAL_PROPS = DetailedHTMLProps<
    HTMLAttributes<HTMLDivElement>,
    HTMLDivElement
> & {
    target?: React.ReactNode;
    targetRef?: React.RefObject<HTMLDivElement>;
    popoverReferenceRef?: React.RefObject<HTMLElement | null>;
    targetWrapperProps?: React.DetailedHTMLProps<
        React.HTMLAttributes<HTMLDivElement>,
        HTMLDivElement
    >;
    setOpen?: React.Dispatch<React.SetStateAction<boolean>>;
    open?: boolean;
    isPopover?: boolean;
    position?: (typeof TWUIPopoverStyles)[number];
    trigger?: (typeof TWUIPopoverTriggers)[number];
    debounce?: number;
    onClose?: () => any;
    hoverOpen?: boolean;
};

/**
 * # Modal Component
 * @ID twui-modal-root
 * @className twui-modal-content
 * @className twui-modal
 * @ID twui-popover-root
 * @className twui-popover-content
 * @className twui-popover-target
 */
export default function Modal(props: TWUI_MODAL_PROPS) {
    const {
        target,
        targetRef,
        targetWrapperProps,
        open: existingOpen,
        setOpen: existingSetOpen,
        isPopover,
        popoverReferenceRef,
        trigger = "hover",
        debounce = 500,
        onClose,
        hoverOpen,
    } = props;

    const [ready, setReady] = React.useState(false);
    const [open, setOpen] = React.useState(existingOpen || false);

    React.useEffect(() => {
        const IDName = isPopover ? "twui-popover-root" : "twui-modal-root";
        const modalRoot = document.getElementById(IDName);

        if (modalRoot) {
            if (isPopover) {
                modalRoot.style.zIndex = "1000";
            }
            setReady(true);
        } else {
            const newModalRootEl = document.createElement("div");
            newModalRootEl.id = IDName;
            document.body.appendChild(newModalRootEl);
            setReady(true);
        }
    }, []);

    React.useEffect(() => {
        existingSetOpen?.(open);
        if (open == false) onClose?.();
    }, [open]);

    React.useEffect(() => {
        setOpen(existingOpen || false);
    }, [existingOpen]);

    const finalTargetRef = targetRef || React.useRef<HTMLDivElement>(null);
    const finalPopoverReferenceRef = popoverReferenceRef || finalTargetRef;

    const popoverTargetActiveRef = React.useRef(false);
    const popoverContentActiveRef = React.useRef(false);

    let closeTimeout: any;

    const popoverEnterFn = React.useCallback((e: any) => {
        popoverTargetActiveRef.current = true;
        popoverContentActiveRef.current = false;
        setOpen(true);
        props.onMouseEnter?.(e);
    }, []);

    const popoverLeaveFn = React.useCallback((e: any) => {
        window.clearTimeout(closeTimeout);
        closeTimeout = setTimeout(() => {
            // if (popoverTargetActiveRef.current) {
            //     popoverTargetActiveRef.current = false;
            //     return;
            // }

            if (popoverContentActiveRef.current) {
                popoverContentActiveRef.current = false;
                return;
            }
            setOpen(false);
        }, debounce);
        props.onMouseLeave?.(e);
    }, []);

    const handleClickOutside = React.useCallback((e: MouseEvent) => {
        const targetEl = e.target as HTMLElement;

        const closestWrapper = targetEl.closest(".twui-popover-content");
        const closestTarget = targetEl.closest(".twui-popover-target");

        if (closestTarget) return;

        if (!closestWrapper) {
            return setOpen(false);
        }
    }, []);

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

    return (
        <React.Fragment>
            {target ? (
                <div
                    {...targetWrapperProps}
                    onClick={(e) => setOpen(!open)}
                    ref={finalTargetRef}
                    onMouseEnter={
                        isPopover && (trigger === "hover" || hoverOpen)
                            ? popoverEnterFn
                            : targetWrapperProps?.onMouseEnter
                    }
                    onMouseLeave={
                        isPopover && (trigger === "hover" || hoverOpen)
                            ? popoverLeaveFn
                            : targetWrapperProps?.onMouseLeave
                    }
                    className={twMerge(
                        "twui-popover-target",
                        targetWrapperProps?.className
                    )}
                >
                    {target}
                </div>
            ) : null}
            {ready ? (
                isPopover ? (
                    <PopoverComponent
                        {...props}
                        open={open}
                        setOpen={setOpen}
                        targetElRef={finalPopoverReferenceRef}
                        debounce={debounce}
                        popoverTargetActiveRef={popoverTargetActiveRef}
                        popoverContentActiveRef={popoverContentActiveRef}
                    />
                ) : (
                    <ModalComponent {...props} open={open} setOpen={setOpen} />
                )
            ) : null}
        </React.Fragment>
    );
}
