import {
  autoPlacement,
  autoUpdate,
  flip,
  FloatingPortal,
  limitShift,
  offset,
  shift,
  size,
  useClick,
  useDismiss,
  useFloating,
  useFocus,
  useInteractions,
  useTransitionStyles,
} from '@floating-ui/react'
import {
  cloneElement,
  createContext,
  Dispatch,
  ReactElement,
  ReactNode,
  SetStateAction,
  useContext,
  useState,
} from 'react'
import { colors } from '../../utils/colors.js'
import { shadows } from '../../utils/shadows.js'
import { radius } from '../../utils/radius.js'
import { useTheme } from '../../hooks/useTheme.js'

type SheetContextType = {
  open: boolean
  setOpen: Dispatch<SetStateAction<boolean>>
  refs: ReturnType<typeof useFloating>['refs']
  floatingStyles: ReturnType<typeof useFloating>['floatingStyles']
  getReferenceProps: ReturnType<typeof useInteractions>['getReferenceProps']
  getFloatingProps: ReturnType<typeof useInteractions>['getFloatingProps']
} | null
const SheetContext = createContext<SheetContextType>(null)

type SheetRootProps = {
  children: ReactNode
}
function Sheet({ children }: SheetRootProps) {
  const [open, setOpen] = useState(false)
  const { refs, floatingStyles, context } = useFloating({
    open,
    onOpenChange: setOpen,
    whileElementsMounted: autoUpdate,
    placement: 'bottom-end',
    middleware: [offset(8), shift()],
  })
  const click = useClick(context, { event: 'click', toggle: true })
  const focus = useFocus(context)
  const dismiss = useDismiss(context, { referencePress: true })
  const { getReferenceProps, getFloatingProps } = useInteractions([
    click,
    focus,
    dismiss,
  ])

  return (
    <SheetContext.Provider
      value={{
        open,
        setOpen,
        refs,
        getReferenceProps,
        getFloatingProps,
        floatingStyles,
      }}
    >
      {children}
    </SheetContext.Provider>
  )
}

type SheetTriggerProps = {
  children: ReactElement | (({ open }: { open: boolean }) => ReactElement)
}
function SheetTrigger({ children }: SheetTriggerProps) {
  const { open, refs, getReferenceProps } = useContext(SheetContext)

  return (
    <>
      {cloneElement(
        typeof children === 'function' ? children({ open }) : children,
        {
          ref: refs.setReference,
          ...getReferenceProps({
            onClick: (e) => {
              typeof children === 'function'
                ? children({ open }).props.onClick?.(e)
                : children.props.onClick?.(e)
            },
          }),
        },
      )}
    </>
  )
}

type SheetContentProps = {
  children: ReactNode
}
function SheetContent({ children }: SheetContentProps) {
  const { theme } = useTheme()
  const { open, refs, floatingStyles, getFloatingProps } =
    useContext(SheetContext)

  if (!open) return null

  return (
    <FloatingPortal>
      <div
        ref={refs.setFloating}
        style={{
          zIndex: 12,
          position: 'fixed',
          borderRadius: radius[16],
          outline: 'none',
          background: colors.neutralInverted100,
          boxShadow: `inset 0 0 0 1px ${colors.neutral10}, ${shadows.popoverLarge}`,
          overflow: 'hidden',
          maxWidth: '100svw',
          ...floatingStyles,
        }}
        {...getFloatingProps()}
      >
        <div
          style={{
            position: 'relative',
            height: '100%',
            width: '100%',
            padding: 8,
            display: 'flex',
            flexDirection: 'column',
            overflow: 'auto',
            scrollbarWidth: 'none',
            gap: 2,
            ...(theme === 'dark' && {
              background: colors.neutral10,
            }),
          }}
        >
          {children}
        </div>
      </div>
    </FloatingPortal>
  )
}

Sheet.Trigger = SheetTrigger
Sheet.Content = SheetContent

export { Sheet }
export type { SheetRootProps, SheetTriggerProps, SheetContentProps }
