import * as React from 'react'
import { motion } from 'framer-motion'
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
import { MOTION_SCALE_IN } from '@/lib/motion'
import { ArrowRightLine, CheckLine } from './icons-inline'
import { getThemeFromDocument } from './theme-from-document'

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

const contentClasses =
  'min-w-32 overflow-hidden rounded-lg border border-border-tertiary bg-bg-container p-1 text-text shadow-lg z-50 outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:!outline-none focus-visible:!ring-0'

export interface DropdownMenuContentProps
  extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> {
  /** When provided (e.g. from ThemeStyleProvider), used for portal wrapper */
  dataStyle?: string
  dataTheme?: string
}

const DropdownMenuContent = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.Content>,
  DropdownMenuContentProps
>(({ className, sideOffset = 4, children, dataStyle, dataTheme, ...props }, ref) => {
  const fromDoc = getThemeFromDocument()
  const dataProps =
    dataStyle !== undefined
      ? { 'data-style': dataStyle, 'data-theme': dataTheme ?? fromDoc['data-theme'] ?? '' }
      : fromDoc
  return (
    <DropdownMenuPrimitive.Portal>
      <div style={{ display: 'contents' }} {...dataProps}>
        <DropdownMenuPrimitive.Content
          ref={ref}
          sideOffset={sideOffset}
          className={cn(contentClasses, className)}
          {...props}
        >
          <motion.div
            {...MOTION_SCALE_IN}
          >
            {children}
          </motion.div>
        </DropdownMenuPrimitive.Content>
      </div>
    </DropdownMenuPrimitive.Portal>
  )
})
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName

const subTriggerVariants = cva(
  'flex h-[var(--select-item-height)] w-full cursor-pointer select-none items-center gap-2 rounded-sm px-[var(--select-item-padding-x)] text-[length:var(--control-font-size-md)] leading-[var(--control-line-height-md)] outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:!outline-none hover:bg-fill-secondary focus:bg-fill-secondary data-[highlighted]:bg-fill-secondary data-[state=open]:bg-fill-secondary',
  {
    variants: {
      inset: { true: 'pl-8 pr-3', false: '' },
    },
    defaultVariants: { inset: false },
  }
)

const DropdownMenuSubTrigger = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> &
    VariantProps<typeof subTriggerVariants> & { subTriggerIcon?: React.ReactNode }
>(({ className, inset = false, children, subTriggerIcon, ...rest }, ref) => (
  <DropdownMenuPrimitive.SubTrigger
    ref={ref}
    className={subTriggerVariants({ inset, className })}
    {...rest}
  >
    {children}
    <span className="ml-auto flex h-4 w-4 items-center justify-center">
      {subTriggerIcon ?? <ArrowRightLine className="h-4 w-4" />}
    </span>
  </DropdownMenuPrimitive.SubTrigger>
))
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName

export interface DropdownMenuSubContentProps
  extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent> {
  /** When provided (e.g. from ThemeStyleProvider), used for portal wrapper */
  dataStyle?: string
  dataTheme?: string
}

const DropdownMenuSubContent = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
  DropdownMenuSubContentProps
>(({ className, sideOffset = 4, dataStyle, dataTheme, ...props }, ref) => {
  const fromDoc = getThemeFromDocument()
  const dataProps =
    dataStyle !== undefined
      ? { 'data-style': dataStyle, 'data-theme': dataTheme ?? fromDoc['data-theme'] ?? '' }
      : fromDoc
  return (
    <DropdownMenuPrimitive.Portal>
      <div style={{ display: 'contents' }} {...dataProps}>
        <DropdownMenuPrimitive.SubContent
          ref={ref}
          sideOffset={sideOffset}
          className={cn(contentClasses, className)}
          {...props}
        />
      </div>
    </DropdownMenuPrimitive.Portal>
  )
})
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName

const itemVariants = cva(
  'relative flex h-[var(--select-item-height)] w-full min-w-0 cursor-pointer select-none items-center gap-2 rounded-sm px-[var(--select-item-padding-x)] text-[length:var(--control-font-size-md)] leading-[var(--control-line-height-md)] outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:!outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
  {
    variants: {
      variant: {
        default:
          'hover:bg-fill-secondary focus:bg-fill-secondary focus:text-text data-[highlighted]:bg-fill-secondary data-[highlighted]:text-text',
        destructive:
          'text-error hover:bg-error-bg focus:bg-error-bg focus:text-error data-[highlighted]:bg-error-bg data-[highlighted]:text-error',
      },
      inset: { true: 'pl-8 pr-3', false: '' },
    },
    defaultVariants: { variant: 'default', inset: false },
  }
)

const DropdownMenuItem = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.Item>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> &
    VariantProps<typeof itemVariants>
>(({ className, inset = false, variant = 'default', ...props }, ref) => (
  <DropdownMenuPrimitive.Item
    ref={ref}
    className={itemVariants({ variant, inset, className })}
    {...props}
  />
))
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName

const itemIndicatorClasses =
  'relative flex h-[var(--select-item-height)] w-full min-w-0 cursor-pointer select-none items-center gap-2 rounded-sm pl-8 pr-3 text-[length:var(--control-font-size-md)] leading-[var(--control-line-height-md)] outline-none transition-colors hover:bg-fill-secondary focus:bg-fill-secondary focus:text-text data-[highlighted]:bg-fill-secondary data-[highlighted]:text-text data-[disabled]:pointer-events-none data-[disabled]:opacity-50'

const DropdownMenuCheckboxItem = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> & { checkIcon?: React.ReactNode }
>(({ className, children, checked, checkIcon, ...rest }, ref) => (
  <DropdownMenuPrimitive.CheckboxItem
    ref={ref}
    className={cn(itemIndicatorClasses, className)}
    checked={checked}
    {...rest}
  >
    <span className="absolute left-2 top-1/2 flex h-3.5 w-3.5 -translate-y-1/2 items-center justify-center">
      <DropdownMenuPrimitive.ItemIndicator>
        {checkIcon ?? <CheckLine className="h-4 w-4" />}
      </DropdownMenuPrimitive.ItemIndicator>
    </span>
    {children}
  </DropdownMenuPrimitive.CheckboxItem>
))
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName

const DropdownMenuRadioItem = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
>(({ className, children, ...props }, ref) => (
  <DropdownMenuPrimitive.RadioItem
    ref={ref}
    className={cn(itemIndicatorClasses, className)}
    {...props}
  >
    <span className="absolute left-2 top-1/2 flex h-3.5 w-3.5 -translate-y-1/2 items-center justify-center">
      <DropdownMenuPrimitive.ItemIndicator>
        <div className="h-2 w-2 rounded-full bg-primary" />
      </DropdownMenuPrimitive.ItemIndicator>
    </span>
    {children}
  </DropdownMenuPrimitive.RadioItem>
))
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName

const labelVariants = cva(
  'flex h-[var(--select-item-height)] items-center px-[var(--select-item-padding-x)] text-[length:var(--control-font-size-md)] leading-[var(--control-line-height-md)] font-semibold text-text-secondary',
  {
    variants: {
      inset: { true: 'pl-8 pr-3', false: '' },
    },
    defaultVariants: { inset: false },
  }
)

const DropdownMenuLabel = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.Label>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> &
    VariantProps<typeof labelVariants>
>(({ className, inset = false, ...props }, ref) => (
  <DropdownMenuPrimitive.Label
    ref={ref}
    className={labelVariants({ inset, className })}
    {...props}
  />
))
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName

const DropdownMenuSeparator = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
>(({ className, ...props }, ref) => (
  <DropdownMenuPrimitive.Separator
    ref={ref}
    className={cn('my-0.5 mx-1 h-px bg-border-tertiary', className)}
    {...props}
  />
))
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName

const DropdownMenuShortcut = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLSpanElement>) => (
  <span
    className={cn('ml-auto text-xs tracking-widest text-text-tertiary', className)}
    {...props}
  />
)
DropdownMenuShortcut.displayName = 'DropdownMenuShortcut'

export {
  DropdownMenu,
  DropdownMenuTrigger,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuCheckboxItem,
  DropdownMenuRadioItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuShortcut,
  DropdownMenuGroup,
  DropdownMenuPortal,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuRadioGroup,
}
