import * as React from 'react'
import { motion } from 'framer-motion'
import * as DialogPrimitive from '@radix-ui/react-dialog'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
import { MOTION_FADE, MOTION_DURATION, MOTION_EASE } from '@/lib/motion'
import { CloseLine } from './icons-inline'
import { getThemeFromDocument } from './theme-from-document'

const Drawer = DialogPrimitive.Root
const DrawerTrigger = DialogPrimitive.Trigger
const DrawerClose = DialogPrimitive.Close
const DrawerPortal = DialogPrimitive.Portal

const DrawerOverlay = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Overlay>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
  <DialogPrimitive.Overlay ref={ref} asChild {...props}>
    <motion.div
      className={cn('fixed inset-0 z-50 bg-bg-mask/60', className)}
      {...MOTION_FADE}
    />
  </DialogPrimitive.Overlay>
))
DrawerOverlay.displayName = DialogPrimitive.Overlay.displayName

const drawerVariants = cva(
  'fixed z-50 gap-4 bg-bg-base text-text shadow-lg border-border p-6 outline-none flex flex-col',
  {
    variants: {
      side: {
        top: 'inset-x-0 top-0 border-b',
        bottom: 'inset-x-0 bottom-0 border-t',
        left: 'inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm',
        right: 'inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm',
      },
    },
    defaultVariants: { side: 'right' },
  },
)

const sideOffsetMap = {
  top: { initial: { y: '-100%' }, animate: { y: 0 }, exit: { y: '-100%' } },
  bottom: { initial: { y: '100%' }, animate: { y: 0 }, exit: { y: '100%' } },
  left: { initial: { x: '-100%' }, animate: { x: 0 }, exit: { x: '-100%' } },
  right: { initial: { x: '100%' }, animate: { x: 0 }, exit: { x: '100%' } },
} as const

export interface DrawerContentProps
  extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,
    VariantProps<typeof drawerVariants> {
  side?: 'top' | 'right' | 'bottom' | 'left'
  showCloseButton?: boolean
  /** When provided (e.g. from ThemeStyleProvider), used for portal wrapper */
  dataStyle?: string
  dataTheme?: string
}

const DrawerContent = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Content>,
  DrawerContentProps
>(
  (
    { side = 'right', className, children, showCloseButton = true, dataStyle, dataTheme, ...props },
    ref,
  ) => {
    const fromDoc = getThemeFromDocument()
    const dataProps =
      dataStyle !== undefined
        ? { 'data-style': dataStyle, 'data-theme': dataTheme ?? fromDoc['data-theme'] ?? '' }
        : fromDoc
    const motionProps = sideOffsetMap[side]
    return (
      <DrawerPortal>
        <div style={{ display: 'contents' }} {...dataProps}>
          <DrawerOverlay />
          <DialogPrimitive.Content ref={ref} asChild {...props}>
            <motion.div
              className={cn(drawerVariants({ side }), className)}
              initial={motionProps.initial}
              animate={motionProps.animate}
              exit={motionProps.exit}
              transition={{ duration: MOTION_DURATION.slow, ease: MOTION_EASE.standard }}
            >
              {children}
              {showCloseButton && (
                <DialogPrimitive.Close
                  className={cn(
                    'absolute right-4 top-4 inline-flex size-7 items-center justify-center rounded-md text-text-tertiary opacity-70 transition-colors',
                    'hover:bg-fill-secondary hover:text-text hover:opacity-100',
                    'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-border',
                    'disabled:pointer-events-none',
                  )}
                >
                  <CloseLine className="size-4" />
                  <span className="sr-only">Close</span>
                </DialogPrimitive.Close>
              )}
            </motion.div>
          </DialogPrimitive.Content>
        </div>
      </DrawerPortal>
    )
  },
)
DrawerContent.displayName = DialogPrimitive.Content.displayName

const DrawerHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
  ({ className, ...props }, ref) => (
    <div ref={ref} className={cn('flex flex-col gap-1.5', className)} {...props} />
  ),
)
DrawerHeader.displayName = 'DrawerHeader'

const DrawerFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
  ({ className, ...props }, ref) => (
    <div ref={ref} className={cn('mt-auto flex flex-col gap-2', className)} {...props} />
  ),
)
DrawerFooter.displayName = 'DrawerFooter'

const DrawerTitle = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Title>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
  <DialogPrimitive.Title
    ref={ref}
    className={cn('text-base font-medium leading-6 text-text', className)}
    {...props}
  />
))
DrawerTitle.displayName = DialogPrimitive.Title.displayName

const DrawerDescription = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Description>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
  <DialogPrimitive.Description
    ref={ref}
    className={cn('text-sm leading-6 text-text-tertiary', className)}
    {...props}
  />
))
DrawerDescription.displayName = DialogPrimitive.Description.displayName

export type DrawerHeaderProps = React.HTMLAttributes<HTMLDivElement>
export type DrawerFooterProps = React.HTMLAttributes<HTMLDivElement>

export {
  Drawer,
  DrawerTrigger,
  DrawerClose,
  DrawerPortal,
  DrawerOverlay,
  DrawerContent,
  DrawerHeader,
  DrawerFooter,
  DrawerTitle,
  DrawerDescription,
  drawerVariants,
}
