"use client";

import * as React from "react";
import { cn } from "@/lib/utils";

type DropdownContextValue = {
  open: boolean;
  setOpen: (v: boolean) => void;
  setTriggerEl: (el: HTMLElement | null) => void;
  getTriggerEl: () => HTMLElement | null;
  contentId: string;
};

const DropdownCtx = React.createContext<DropdownContextValue | null>(null);

function useDropdownContext() {
  const ctx = React.useContext(DropdownCtx);
  if (!ctx)
    throw new Error("DropdownMenu primitives must be used inside <DropdownMenu>");
  return ctx;
}

export function DropdownMenu({
  children,
  defaultOpen = false,
  onOpenChange,
}: {
  children: React.ReactNode;
  defaultOpen?: boolean;
  onOpenChange?: (open: boolean) => void;
}) {
  const [open, setOpenState] = React.useState(defaultOpen);
  const triggerElRef = React.useRef<HTMLElement | null>(null);
  const id = React.useId();
  const setOpen = React.useCallback(
    (v: boolean) => {
      setOpenState(v);
      onOpenChange?.(v);
    },
    [onOpenChange],
  );
  const setTriggerEl = React.useCallback((el: HTMLElement | null) => {
    triggerElRef.current = el;
  }, []);
  const getTriggerEl = React.useCallback(() => triggerElRef.current, []);
  const value = React.useMemo(
    () => ({
      open,
      setOpen,
      setTriggerEl,
      getTriggerEl,
      contentId: `dropdown-${id}`,
    }),
    [open, setOpen, setTriggerEl, getTriggerEl, id],
  );
  return (
    <DropdownCtx.Provider value={value}>
      <div className="relative inline-block">{children}</div>
    </DropdownCtx.Provider>
  );
}

export function DropdownMenuTrigger({
  children,
  className,
}: {
  children: React.ReactNode;
  className?: string;
}) {
  const ctx = useDropdownContext();
  const { open, setOpen, setTriggerEl, contentId } = ctx;
  return (
    <button
      ref={setTriggerEl}
      type="button"
      aria-haspopup="menu"
      aria-expanded={open}
      aria-controls={contentId}
      onClick={() => setOpen(!open)}
      className={cn("outline-none", className)}
    >
      {children}
    </button>
  );
}

export function DropdownMenuContent({
  children,
  className,
  align = "start",
}: {
  children: React.ReactNode;
  className?: string;
  align?: "start" | "end";
}) {
  const ctx = useDropdownContext();
  const ref = React.useRef<HTMLDivElement | null>(null);

  React.useEffect(() => {
    if (!ctx.open) return;
    function handleClick(e: MouseEvent) {
      const target = e.target as Node;
      const trigger = ctx.getTriggerEl();
      if (
        ref.current &&
        !ref.current.contains(target) &&
        trigger &&
        !trigger.contains(target)
      ) {
        ctx.setOpen(false);
      }
    }
    function handleKey(e: KeyboardEvent) {
      if (e.key === "Escape") ctx.setOpen(false);
    }
    document.addEventListener("mousedown", handleClick);
    document.addEventListener("keydown", handleKey);
    return () => {
      document.removeEventListener("mousedown", handleClick);
      document.removeEventListener("keydown", handleKey);
    };
  }, [ctx]);

  if (!ctx.open) return null;
  return (
    <div
      ref={ref}
      role="menu"
      id={ctx.contentId}
      className={cn(
        "absolute z-50 mt-1 min-w-44 rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
        align === "end" ? "right-0" : "left-0",
        className,
      )}
    >
      {children}
    </div>
  );
}

export function DropdownMenuItem({
  children,
  onSelect,
  destructive,
  disabled,
  className,
}: {
  children: React.ReactNode;
  onSelect?: () => void;
  destructive?: boolean;
  disabled?: boolean;
  className?: string;
}) {
  const ctx = useDropdownContext();
  return (
    <button
      type="button"
      role="menuitem"
      disabled={disabled}
      onClick={() => {
        if (disabled) return;
        onSelect?.();
        ctx.setOpen(false);
      }}
      className={cn(
        "flex w-full items-center gap-2 rounded-sm px-2.5 py-1.5 text-left text-sm transition-colors",
        "hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:outline-none",
        "disabled:pointer-events-none disabled:opacity-50",
        destructive && "text-destructive hover:text-destructive",
        className,
      )}
    >
      {children}
    </button>
  );
}

export function DropdownMenuSeparator({ className }: { className?: string }) {
  return (
    <div
      role="separator"
      aria-orientation="horizontal"
      className={cn("my-1 h-px bg-border", className)}
    />
  );
}

export function DropdownMenuLabel({
  children,
  className,
}: {
  children: React.ReactNode;
  className?: string;
}) {
  return (
    <div className={cn("px-2.5 py-1.5 section-label", className)}>{children}</div>
  );
}
