import { createContext, JSXElement, useContext } from "solid-js";
import { FloatingRoot, FloatingTrigger, FloatingContent, useFloatingHover, Placement } from "./Floating.tsx";

const POPOVER_CLS = "bg-surface rounded-default shadow-lg border border-line";

interface PopoverProps {
    open?: boolean;
    onOpenChange?: (open: boolean) => void;
    placement?: Placement;
    offset?: number;
    // Nested floating that shouldn't close (or be closed by) an ancestor popover.
    standalone?: boolean;
    children?: JSXElement;
}

interface HoverPopoverProps extends PopoverProps {
    hoverDelay?: number;
    hoverCloseDelay?: number;
}

export function Popover(props: PopoverProps) {
    return (
        <FloatingRoot open={props.open} onOpenChange={(v: boolean) => props.onOpenChange?.(v)} placement={props.placement ?? "bottom-start"} offset={props.offset ?? 8} flip={true} shift={true} standalone={props.standalone}>
            {props.children}
        </FloatingRoot>
    );
}

interface PopoverTriggerProps {
    class?: string;
    title?: string;
    children?: JSXElement;
}

export function PopoverTrigger(props: PopoverTriggerProps) {
    return (
        <FloatingTrigger openOnHover={false} class={props.class || ""} title={props.title}>
            {props.children}
        </FloatingTrigger>
    );
}

interface PopoverContentProps {
    class?: string;
    style?: Record<string, string | number>;
    children?: JSXElement;
}

export function PopoverContent(props: PopoverContentProps) {
    return (
        <FloatingContent class={POPOVER_CLS + " " + (props.class || "")} style={props.style}>
            {props.children}
        </FloatingContent>
    );
}

export function HoverPopover(props: HoverPopoverProps) {
    return (
        <FloatingRoot open={props.open} onOpenChange={(v: boolean) => props.onOpenChange?.(v)} placement={props.placement ?? "bottom-start"} offset={props.offset ?? 8} flip={true} shift={true} standalone={props.standalone}>
            <HoverPopoverInner hoverDelay={props.hoverDelay ?? 0} hoverCloseDelay={props.hoverCloseDelay ?? 150}>
                {props.children}
            </HoverPopoverInner>
        </FloatingRoot>
    );
}

interface HoverPopoverContextValue {
    hoverDelay: number;
    hoverCloseDelay: number;
}

const HoverPopoverContext = createContext<HoverPopoverContextValue | null>(null);

interface HoverPopoverInnerProps {
    hoverDelay: number;
    hoverCloseDelay: number;
    children?: JSXElement;
}

function HoverPopoverInner(props: HoverPopoverInnerProps) {
    return (
        <HoverPopoverContext.Provider value={{
            get hoverDelay() { return props.hoverDelay; },
            get hoverCloseDelay() { return props.hoverCloseDelay; },
        }}>
            {props.children}
        </HoverPopoverContext.Provider>
    );
}

interface HoverPopoverTriggerProps {
    asChild?: boolean;
    class?: string;
    children?: JSXElement;
}

export function HoverPopoverTrigger(props: HoverPopoverTriggerProps) {
    const ctx = useContext(HoverPopoverContext);
    return (
        <FloatingTrigger openOnHover={true} class={props.class || ""} hoverDelay={ctx?.hoverDelay ?? 0} hoverCloseDelay={ctx?.hoverCloseDelay ?? 150}>
            {props.children}
        </FloatingTrigger>
    );
}

export function HoverPopoverContent(props: PopoverContentProps) {
    const ctx = useContext(HoverPopoverContext);
    const hoverProps = useFloatingHover(true, ctx?.hoverCloseDelay ?? 150);

    return (
        <FloatingContent class={POPOVER_CLS + " " + (props.class || "")} style={props.style} onMouseEnter={hoverProps.onMouseEnter} onMouseLeave={hoverProps.onMouseLeave}>
            {props.children}
        </FloatingContent>
    );
}
