import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import {
  forwardRef,
  type ComponentPropsWithoutRef,
  type ElementRef,
  type HTMLAttributes
} from "react";

import {
  dropdownMenuContentVariants,
  dropdownMenuItemVariants,
  dropdownMenuLabelVariants,
  dropdownMenuSeparatorVariants
} from "./dropdown-menu.variants";
import { cn } from "../lib/cn";
import type { VariantProps } from "../lib/cva";
import { createDataAttributes, createSlot } from "../lib/contracts";

export const DropdownMenu = DropdownMenuPrimitive.Root;
export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
export const DropdownMenuGroup = DropdownMenuPrimitive.Group;
export const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
export const DropdownMenuSub = DropdownMenuPrimitive.Sub;
export const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;

export type DropdownMenuContentProps =
  ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> &
    VariantProps<typeof dropdownMenuContentVariants>;

export const DropdownMenuContent = forwardRef<
  ElementRef<typeof DropdownMenuPrimitive.Content>,
  DropdownMenuContentProps
>(function DropdownMenuContent(
  { className, sideOffset = 8, size, ...props },
  ref
) {
  return (
    <DropdownMenuPortal>
      <DropdownMenuPrimitive.Content
        {...props}
        {...createSlot("content")}
        {...createDataAttributes({ size })}
        className={cn(dropdownMenuContentVariants({ size }), className)}
        ref={ref}
        sideOffset={sideOffset}
      />
    </DropdownMenuPortal>
  );
});

export type DropdownMenuSubContentProps =
  ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent> &
    VariantProps<typeof dropdownMenuContentVariants>;

export const DropdownMenuSubContent = forwardRef<
  ElementRef<typeof DropdownMenuPrimitive.SubContent>,
  DropdownMenuSubContentProps
>(function DropdownMenuSubContent(
  { className, sideOffset = 10, size, ...props },
  ref
) {
  return (
    <DropdownMenuPortal>
      <DropdownMenuPrimitive.SubContent
        {...props}
        {...createSlot("content")}
        {...createDataAttributes({ size })}
        className={cn(dropdownMenuContentVariants({ size }), className)}
        ref={ref}
        sideOffset={sideOffset}
      />
    </DropdownMenuPortal>
  );
});

export type DropdownMenuItemProps =
  ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> &
    VariantProps<typeof dropdownMenuItemVariants>;

export const DropdownMenuItem = forwardRef<
  ElementRef<typeof DropdownMenuPrimitive.Item>,
  DropdownMenuItemProps
>(function DropdownMenuItem(
  { className, inset, variant, ...props },
  ref
) {
  return (
    <DropdownMenuPrimitive.Item
      {...props}
      {...createSlot("item")}
      {...createDataAttributes({ inset, variant })}
      className={cn(dropdownMenuItemVariants({ inset, variant }), className)}
      ref={ref}
    />
  );
});

export type DropdownMenuCheckboxItemProps =
  ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> &
    VariantProps<typeof dropdownMenuItemVariants>;

export const DropdownMenuCheckboxItem = forwardRef<
  ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
  DropdownMenuCheckboxItemProps
>(function DropdownMenuCheckboxItem(
  { checked, children, className, inset = true, variant, ...props },
  ref
) {
  return (
    <DropdownMenuPrimitive.CheckboxItem
      {...props}
      checked={checked}
      {...createSlot("item")}
      {...createDataAttributes({ checked: checked === true, inset, variant })}
      className={cn(dropdownMenuItemVariants({ inset, variant }), className)}
      ref={ref}
    >
      <span
        {...createSlot("icon")}
        className="absolute left-2.5 inline-flex size-4 items-center justify-center text-xs"
      >
        <DropdownMenuPrimitive.ItemIndicator>✓</DropdownMenuPrimitive.ItemIndicator>
      </span>
      {children}
    </DropdownMenuPrimitive.CheckboxItem>
  );
});

export type DropdownMenuRadioItemProps =
  ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> &
    VariantProps<typeof dropdownMenuItemVariants>;

export const DropdownMenuRadioItem = forwardRef<
  ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
  DropdownMenuRadioItemProps
>(function DropdownMenuRadioItem(
  { children, className, inset = true, variant, ...props },
  ref
) {
  return (
    <DropdownMenuPrimitive.RadioItem
      {...props}
      {...createSlot("item")}
      {...createDataAttributes({ inset, variant })}
      className={cn(dropdownMenuItemVariants({ inset, variant }), className)}
      ref={ref}
    >
      <span
        {...createSlot("icon")}
        className="absolute left-2.5 inline-flex size-4 items-center justify-center text-xs"
      >
        <DropdownMenuPrimitive.ItemIndicator>•</DropdownMenuPrimitive.ItemIndicator>
      </span>
      {children}
    </DropdownMenuPrimitive.RadioItem>
  );
});

export type DropdownMenuLabelProps =
  ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> &
    VariantProps<typeof dropdownMenuLabelVariants>;

export const DropdownMenuLabel = forwardRef<
  ElementRef<typeof DropdownMenuPrimitive.Label>,
  DropdownMenuLabelProps
>(function DropdownMenuLabel({ className, inset, ...props }, ref) {
  return (
    <DropdownMenuPrimitive.Label
      {...props}
      {...createSlot("label")}
      {...createDataAttributes({ inset })}
      className={cn(dropdownMenuLabelVariants({ inset }), className)}
      ref={ref}
    />
  );
});

export const DropdownMenuSeparator = forwardRef<
  ElementRef<typeof DropdownMenuPrimitive.Separator>,
  ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
>(function DropdownMenuSeparator({ className, ...props }, ref) {
  return (
    <DropdownMenuPrimitive.Separator
      {...props}
      {...createSlot("separator")}
      className={cn(dropdownMenuSeparatorVariants(), className)}
      ref={ref}
    />
  );
});

export type DropdownMenuSubTriggerProps =
  ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> &
    VariantProps<typeof dropdownMenuItemVariants>;

export const DropdownMenuSubTrigger = forwardRef<
  ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
  DropdownMenuSubTriggerProps
>(function DropdownMenuSubTrigger(
  { children, className, inset, variant, ...props },
  ref
) {
  return (
    <DropdownMenuPrimitive.SubTrigger
      {...props}
      {...createSlot("trigger")}
      {...createDataAttributes({ inset, variant })}
      className={cn(dropdownMenuItemVariants({ inset, variant }), className)}
      ref={ref}
    >
      {children}
      <span className="ml-auto text-xs text-[var(--color-muted-foreground)]">›</span>
    </DropdownMenuPrimitive.SubTrigger>
  );
});

export function DropdownMenuShortcut({
  className,
  ...props
}: HTMLAttributes<HTMLSpanElement>) {
  return (
    <span
      {...props}
      {...createSlot("shortcut")}
      className={cn(
        "ml-auto text-xs uppercase tracking-[var(--tracking-caps)] text-[var(--color-muted-foreground)]",
        className
      )}
    />
  );
}
