'use client'

import * as React from 'react'
import type { ContentEditorSlashCommand } from '@admin/utils/editor/slash-commands'
import type { SlashMenuState } from '@admin/utils/editor/slash-menu-state'
import {
  Combobox,
  ComboboxContent,
  ComboboxEmpty,
  ComboboxInput,
  ComboboxItem,
  ComboboxList
} from '@admin/components/ui/combobox'
import { cn } from '@admin/utils/shared/cn'

export function SlashCommandMenu({
  activeIndex,
  commands,
  onActiveIndexChange,
  onClose,
  onCommandSelect,
  onSearchChange,
  slashMenu,
  searchQuery
}: {
  activeIndex: number
  commands: ContentEditorSlashCommand[]
  onActiveIndexChange: (index: number) => void
  onClose: () => void
  onCommandSelect: (command: ContentEditorSlashCommand) => void
  onSearchChange: (query: string) => void
  slashMenu: SlashMenuState | null
  searchQuery: string
}) {
  const activeItemRef = React.useRef<HTMLDivElement | null>(null)
  const searchInputRef = React.useRef<HTMLInputElement | null>(null)
  const activeCommandId = commands[activeIndex]?.id

  const handleSearchKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
    const stopComboboxKeyHandling = () => {
      const baseUIEvent = event as React.KeyboardEvent<HTMLInputElement> & {
        preventBaseUIHandler?: () => void
      }

      event.preventDefault()
      event.stopPropagation()
      baseUIEvent.preventBaseUIHandler?.()
    }

    if (event.key === 'ArrowDown') {
      stopComboboxKeyHandling()
      onActiveIndexChange(commands.length > 0 ? (activeIndex + 1) % commands.length : 0)
      return
    }

    if (event.key === 'ArrowUp') {
      stopComboboxKeyHandling()
      onActiveIndexChange(
        commands.length > 0 ? (activeIndex - 1 + commands.length) % commands.length : 0
      )
      return
    }

    if (event.key === 'Escape') {
      stopComboboxKeyHandling()
      onClose()
      return
    }

    if (event.key === 'Enter' || event.key === 'Tab') {
      const command = commands[activeIndex]
      if (!command) return

      stopComboboxKeyHandling()
      onCommandSelect(command)
    }
  }

  React.useEffect(() => {
    if (!slashMenu) return

    const focusSearchInput = () => {
      searchInputRef.current?.focus({ preventScroll: true })
      searchInputRef.current?.select()
    }

    focusSearchInput()
    const frame = requestAnimationFrame(focusSearchInput)

    return () => cancelAnimationFrame(frame)
  }, [slashMenu])

  React.useEffect(() => {
    if (!activeCommandId) return

    activeItemRef.current?.scrollIntoView({ block: 'nearest' })
  }, [activeCommandId])

  if (!slashMenu) return null

  const slashAnchor = {
    getBoundingClientRect: () => slashMenu.rect
  }

  return (
    <Combobox<ContentEditorSlashCommand>
      autoHighlight
      filter={null}
      filteredItems={commands}
      inputValue={searchQuery}
      itemToStringLabel={(command) => command.title}
      itemToStringValue={(command) => command.id}
      items={commands}
      onInputValueChange={onSearchChange}
      onItemHighlighted={(command) => {
        if (!command) return

        const nextIndex = commands.findIndex((item) => item.id === command.id)
        if (nextIndex >= 0) onActiveIndexChange(nextIndex)
      }}
      onOpenChange={(isOpen) => {
        if (!isOpen) onClose()
      }}
      onValueChange={(command) => {
        if (command) onCommandSelect(command)
      }}
      open
      value={null}
    >
      <ComboboxContent
        anchor={slashAnchor}
        align="start"
        className="flex w-72 max-w-[calc(100vw-2rem)] min-w-72 flex-col gap-2 p-2"
        collisionPadding={8}
        finalFocus={false}
        initialFocus={false}
        positionMethod="fixed"
        side="bottom"
        sideOffset={8}
        data-content-editor-slash-menu
      >
        <ComboboxInput
          aria-label="Search commands"
          ref={searchInputRef}
          onKeyDown={handleSearchKeyDown}
          placeholder="Search commands..."
          showClear
          showTrigger={false}
          className="border border-border"
        />
        <ComboboxEmpty className="py-6">No commands found</ComboboxEmpty>
        <ComboboxList className="max-h-80 p-0">
          {commands.map((command, index) => {
            const Icon = command.Icon
            const isActive = index === activeIndex

            return (
              <ComboboxItem
                index={index}
                key={command.id}
                data-active={isActive ? 'true' : undefined}
                ref={(node) => {
                  if (isActive) activeItemRef.current = node
                }}
                onMouseDown={(event) => event.preventDefault()}
                onMouseEnter={() => onActiveIndexChange(index)}
                value={command}
                className={cn(
                  'border border-transparent p-2 data-highlighted:border-border! data-highlighted:bg-card!',
                  {
                    'border-border bg-card text-foreground shadow-input': isActive
                  }
                )}
              >
                <span className="flex size-8 shrink-0 items-center justify-center rounded-sm border border-border bg-card shadow-input">
                  <Icon />
                </span>
                <span className="flex w-full min-w-0 flex-col space-y-1">
                  <span className="leading-none font-medium">{command.title}</span>
                  <span className="truncate text-xs text-muted-foreground">
                    {command.description}
                  </span>
                </span>
              </ComboboxItem>
            )
          })}
        </ComboboxList>
      </ComboboxContent>
    </Combobox>
  )
}
