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

const ContextMenu = ContextMenuPrimitive.Root
const ContextMenuTrigger = ContextMenuPrimitive.Trigger
const ContextMenuGroup = ContextMenuPrimitive.Group
const ContextMenuPortal = ContextMenuPrimitive.Portal
const ContextMenuSub = ContextMenuPrimitive.Sub
const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup

const contentClasses =
  'z-50 min-w-36 overflow-hidden rounded-lg border border-border-tertiary bg-bg-container p-1 text-text shadow-lg 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 ContextMenuContentProps
  extends React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content> {
  dataStyle?: string
  dataTheme?: string
}

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

const subTriggerVariants = cva(
  'flex h-[var(--select-item-height)] w-full cursor-pointer select-none items-center gap-2 rounded-md 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 focus-visible:!ring-0 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 ContextMenuSubTrigger = React.forwardRef<
  React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
  React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> &
    VariantProps<typeof subTriggerVariants>
>(({ className, inset = false, children, ...props }, ref) => (
  <ContextMenuPrimitive.SubTrigger
    ref={ref}
    className={cn(subTriggerVariants({ inset }), className)}
    {...props}
  >
    {children}
    <span className="ml-auto flex h-4 w-4 items-center justify-center">
      <ArrowRightSLine className="h-4 w-4" />
    </span>
  </ContextMenuPrimitive.SubTrigger>
))
ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName

const ContextMenuSubContent = React.forwardRef<
  React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
  React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent> & {
    dataStyle?: string
    dataTheme?: string
  }
>(({ 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 (
    <ContextMenuPrimitive.Portal>
      <div style={{ display: 'contents' }} {...dataProps}>
        <ContextMenuPrimitive.SubContent
          ref={ref}
          sideOffset={sideOffset}
          className={cn(contentClasses, className)}
          {...props}
        />
      </div>
    </ContextMenuPrimitive.Portal>
  )
})
ContextMenuSubContent.displayName = ContextMenuPrimitive.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-md 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 focus-visible:!ring-0 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 ContextMenuItem = React.forwardRef<
  React.ElementRef<typeof ContextMenuPrimitive.Item>,
  React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> &
    VariantProps<typeof itemVariants>
>(({ className, inset = false, variant = 'default', ...props }, ref) => (
  <ContextMenuPrimitive.Item
    ref={ref}
    className={cn(itemVariants({ variant, inset }), className)}
    {...props}
  />
))
ContextMenuItem.displayName = ContextMenuPrimitive.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-md pl-8 pr-2 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 focus-visible:!ring-0 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 ContextMenuCheckboxItem = React.forwardRef<
  React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
  React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>
>(({ className, children, checked, ...rest }, ref) => (
  <ContextMenuPrimitive.CheckboxItem
    ref={ref}
    checked={checked}
    className={cn(itemIndicatorClasses, className)}
    {...rest}
  >
    <span className="absolute left-2 top-1/2 flex h-3.5 w-3.5 -translate-y-1/2 items-center justify-center">
      <ContextMenuPrimitive.ItemIndicator>
        <CheckLine className="h-4 w-4" />
      </ContextMenuPrimitive.ItemIndicator>
    </span>
    {children}
  </ContextMenuPrimitive.CheckboxItem>
))
ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName

const ContextMenuRadioItem = React.forwardRef<
  React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
  React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
>(({ className, children, ...props }, ref) => (
  <ContextMenuPrimitive.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">
      <ContextMenuPrimitive.ItemIndicator>
        <div className="h-2 w-2 rounded-full bg-primary" />
      </ContextMenuPrimitive.ItemIndicator>
    </span>
    {children}
  </ContextMenuPrimitive.RadioItem>
))
ContextMenuRadioItem.displayName = ContextMenuPrimitive.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 ContextMenuLabel = React.forwardRef<
  React.ElementRef<typeof ContextMenuPrimitive.Label>,
  React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> &
    VariantProps<typeof labelVariants>
>(({ className, inset = false, ...props }, ref) => (
  <ContextMenuPrimitive.Label
    ref={ref}
    className={cn(labelVariants({ inset }), className)}
    {...props}
  />
))
ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName

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

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

export {
  ContextMenu,
  ContextMenuTrigger,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuCheckboxItem,
  ContextMenuRadioItem,
  ContextMenuLabel,
  ContextMenuSeparator,
  ContextMenuShortcut,
  ContextMenuGroup,
  ContextMenuPortal,
  ContextMenuSub,
  ContextMenuSubContent,
  ContextMenuSubTrigger,
  ContextMenuRadioGroup,
}
