'use client'

import * as PopoverPrimitive from '@radix-ui/react-popover'
import * as React from 'react'
import {
  SvgTaillessLineArrowDown1,
  SvgTaillessLineArrowUp1,
} from '@chainlink/blocks-icons'
import { cn, getIconUrl } from '../../utils'
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from '../Command'
import { inputVariants } from '../Input'
import { ClearIcon } from '../Input/icons'
import { Popover, PopoverTrigger } from '../Popover'
import { typographyVariants } from '../Typography'

/**
 * Custom PopoverContent for LegacyCombobox that doesn't use a Portal.
 * This allows the content to stay within the DOM hierarchy,
 * which is required for proper scrolling inside modal dialogs (SidePanel, Sheet, etc.)
 */
const LegacyComboboxPopoverContent = React.forwardRef<
  React.ElementRef<typeof PopoverPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
  <PopoverPrimitive.Content
    ref={ref}
    sideOffset={sideOffset}
    className={cn('pointer-events-auto', className)}
    {...props}
  />
))
LegacyComboboxPopoverContent.displayName = 'LegacyComboboxPopoverContent'

export interface LegacyComboboxProps {
  size?: 'default' | 'sm'
  disabled?: boolean
  clearable?: boolean
  placeholder?: string
  value?: string
  onValueChange?: (value: string) => void
  defaultOpen?: boolean
  children: React.ReactNode
}

interface LegacyComboboxContextValue {
  open: boolean
  setOpen: (open: boolean) => void
  value: string
  setValue: (value: string) => void
  size: 'default' | 'sm'
  disabled: boolean
  clearable: boolean
  placeholder: string
  compact: boolean
  setCompact: (compact: boolean) => void
  selectedContent: React.ReactNode | null
  setSelectedContent: (content: React.ReactNode | null) => void
}

const LegacyComboboxContext = React.createContext<
  LegacyComboboxContextValue | undefined
>(undefined)

const useLegacyComboboxContext = () => {
  const context = React.useContext(LegacyComboboxContext)
  if (!context) {
    throw new Error(
      'LegacyCombobox components must be used within a LegacyCombobox',
    )
  }
  return context
}

export function LegacyCombobox({
  size = 'default',
  disabled = false,
  clearable = true,
  placeholder = 'Select...',
  value: controlledValue,
  onValueChange,
  defaultOpen = false,
  children,
}: LegacyComboboxProps) {
  const [open, setOpen] = React.useState(defaultOpen)
  const [internalValue, setInternalValue] = React.useState('')
  const [compact, setCompact] = React.useState(false)
  const [selectedContent, setSelectedContent] =
    React.useState<React.ReactNode | null>(null)

  const value = controlledValue !== undefined ? controlledValue : internalValue
  const setValue = (newValue: string) => {
    if (controlledValue === undefined) {
      setInternalValue(newValue)
    }
    onValueChange?.(newValue)
  }

  return (
    <LegacyComboboxContext.Provider
      value={{
        open,
        setOpen,
        value,
        setValue,
        size,
        disabled,
        clearable,
        placeholder,
        compact,
        setCompact,
        selectedContent,
        setSelectedContent,
      }}
    >
      <Popover open={open} onOpenChange={setOpen}>
        {children}
      </Popover>
    </LegacyComboboxContext.Provider>
  )
}

type LegacyComboboxIconProps = React.HTMLAttributes<HTMLDivElement> & {
  ref?: React.Ref<HTMLDivElement>
}

const LegacyComboboxIcon = ({
  className,
  ref,
  ...props
}: LegacyComboboxIconProps) => {
  const { size } = useLegacyComboboxContext()

  return (
    <div
      ref={ref}
      data-slot="combobox-icon"
      data-size={size}
      className={cn(
        'text-input-muted-foreground',
        'data-[size=default]:h-4 data-[size=sm]:h-3 data-[size=default]:w-4 data-[size=sm]:w-3',
        '[&_svg]:h-full [&_svg]:w-full [&_svg]:text-input-muted-foreground',
        className,
      )}
      {...props}
    >
      <SvgTaillessLineArrowDown1 />
    </div>
  )
}
LegacyComboboxIcon.displayName = 'LegacyComboboxIcon'

const LegacyComboboxClearIcon = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
  const { size, value, setValue, setSelectedContent, disabled, clearable } =
    useLegacyComboboxContext()

  if (!value || disabled || !clearable) return null

  const handleClear = (event: React.MouseEvent | React.KeyboardEvent) => {
    event.stopPropagation()
    event.preventDefault()
    setValue('')
    setSelectedContent(null)
  }

  return (
    <div
      ref={ref}
      role="button"
      tabIndex={0}
      data-slot="combobox-clear"
      data-size={size}
      aria-label="Clear selection"
      onClick={handleClear}
      onKeyDown={(event) => {
        if (event.key === 'Enter' || event.key === ' ') {
          handleClear(event)
        }
      }}
      className={cn(
        'pointer-events-none cursor-pointer opacity-0 transition-opacity',
        'group-hover:pointer-events-auto group-hover:opacity-100',
        'focus:pointer-events-auto focus:opacity-100',
        'text-input-muted-foreground hover:text-muted-foreground focus-visible:text-muted-foreground',
        'focus-visible:rounded-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring',
        'data-[size=default]:h-4 data-[size=sm]:h-3 data-[size=default]:w-4 data-[size=sm]:w-3',
        '[&_svg]:h-full [&_svg]:w-full',
        className,
      )}
      {...props}
    >
      <ClearIcon />
    </div>
  )
})
LegacyComboboxClearIcon.displayName = 'LegacyComboboxClearIcon'

interface LegacyComboboxTriggerProps {
  className?: string
  children: React.ReactNode
  asChild?: boolean
  hideIcon?: boolean
}

export function LegacyComboboxTrigger({
  className,
  children,
  asChild = false,
  hideIcon = false,
}: LegacyComboboxTriggerProps) {
  const { open, disabled, size, compact } = useLegacyComboboxContext()

  const iconRotationStyles =
    '[&_[data-slot=combobox-icon]]:transition-transform [&_[data-slot=combobox-icon]]:duration-100 [&_[data-slot=combobox-icon]]:data-[state=open]:rotate-180'

  if (asChild) {
    return (
      <PopoverTrigger
        asChild
        data-slot="combobox-trigger"
        data-size={size}
        data-state={open ? 'open' : 'closed'}
        className={cn(iconRotationStyles, className)}
      >
        {children}
      </PopoverTrigger>
    )
  }

  return (
    <PopoverTrigger
      data-slot="combobox-trigger"
      data-size={size}
      data-state={open ? 'open' : 'closed'}
      disabled={disabled}
      className={cn(
        'group',
        inputVariants({ size }),
        typographyVariants({
          variant: size === 'default' ? 'body-s' : 'body-xs',
        }),
        'flex w-full items-center justify-between whitespace-nowrap text-foreground',
        compact ? 'w-fit md:w-fit' : 'w-full md:w-[256px]',
        'hover:border-input-border-active data-[state=open]:border-input-border-active',
        disabled && 'pointer-events-none hover:border-input-border',
        '[&_[data-slot=combobox-value]]:line-clamp-1 [&_[data-slot=combobox-value]]:text-foreground',
        '[&_[data-slot=combobox-value][data-placeholder=true]]:text-input-muted-foreground',
        iconRotationStyles,
        disabled && 'cursor-not-allowed opacity-50',
        className,
      )}
    >
      {children}
      <div className="flex items-center gap-2">
        <LegacyComboboxClearIcon />
        {!hideIcon && <LegacyComboboxIcon />}
      </div>
    </PopoverTrigger>
  )
}

interface LegacyComboboxValueProps {
  placeholder?: string
  hideText?: boolean
  children?: React.ReactNode
}

export function LegacyComboboxValue({
  placeholder: customPlaceholder,
  hideText,
  children,
}: LegacyComboboxValueProps) {
  const { value, placeholder, selectedContent, setCompact, size } =
    useLegacyComboboxContext()

  React.useEffect(() => {
    setCompact(!!hideText)
  }, [hideText, setCompact])

  const showPlaceholder = !value
  const content =
    children ||
    (showPlaceholder ? customPlaceholder || placeholder : selectedContent)

  return (
    <span
      data-slot="combobox-value"
      data-placeholder={showPlaceholder}
      data-hide-text={!!hideText}
      className={cn(
        '!flex flex-row items-center gap-2 truncate font-sans',
        size === 'default' ? 'text-sm leading-5' : 'text-xs leading-4',
        hideText && 'text-[0] leading-none',
      )}
    >
      {content}
    </span>
  )
}

interface LegacyComboboxContentProps {
  children: React.ReactNode
  className?: string
}

export function LegacyComboboxContent({
  children,
  className,
}: LegacyComboboxContentProps) {
  const { size, open, compact } = useLegacyComboboxContext()
  const listRef = React.useRef<HTMLDivElement | null>(null)
  const scrollIntervalRef = React.useRef<ReturnType<typeof setInterval> | null>(
    null,
  )
  const [showScrollDown, setShowScrollDown] = React.useState(false)
  const [showScrollUp, setShowScrollUp] = React.useState(false)

  const handleScroll = React.useCallback(() => {
    const el = listRef.current
    if (!el) return
    const { scrollTop, clientHeight, scrollHeight } = el
    setShowScrollDown(scrollTop + clientHeight < scrollHeight - 1)
    setShowScrollUp(scrollTop > 1)
  }, [])

  const stopAutoScroll = React.useCallback(() => {
    if (scrollIntervalRef.current) {
      clearInterval(scrollIntervalRef.current)
      scrollIntervalRef.current = null
    }
  }, [])

  const startAutoScroll = React.useCallback(
    (direction: 'up' | 'down') => {
      stopAutoScroll()
      scrollIntervalRef.current = setInterval(() => {
        const el = listRef.current
        if (!el) return
        const atBoundary =
          direction === 'down'
            ? el.scrollTop + el.clientHeight >= el.scrollHeight - 1
            : el.scrollTop <= 1
        if (atBoundary) {
          stopAutoScroll()
          handleScroll()
          return
        }
        el.scrollTop += direction === 'down' ? 4 : -4
        handleScroll()
      }, 16)
    },
    [handleScroll, stopAutoScroll],
  )

  const scrollToTop = React.useCallback(() => {
    requestAnimationFrame(() => {
      if (listRef.current) {
        listRef.current.scrollTop = 0
      }
      handleScroll()
    })
  }, [handleScroll])

  React.useEffect(() => {
    if (!listRef.current) return
    const ro = new ResizeObserver(() => handleScroll())
    ro.observe(listRef.current)

    handleScroll()

    return () => {
      ro.disconnect()
    }
  }, [handleScroll])

  React.useEffect(() => {
    if (open) {
      requestAnimationFrame(() => handleScroll())
    } else {
      stopAutoScroll()
    }
  }, [open, handleScroll, stopAutoScroll])

  React.useEffect(() => {
    return () => stopAutoScroll()
  }, [stopAutoScroll])

  return (
    <LegacyComboboxPopoverContent
      align="start"
      side="bottom"
      sideOffset={4}
      className={cn(
        'pointer-events-auto',
        typographyVariants({ variant: 'body-s', color: 'muted' }),
        'relative z-50 overflow-hidden rounded border border-solid border-input-border-active bg-background p-0',
        compact
          ? 'w-[256px] max-w-[256px]'
          : 'w-[var(--radix-popover-trigger-width)] max-w-[var(--radix-popover-trigger-width)]',
        'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
        className,
      )}
    >
      <Command className="w-full">
        <CommandInput
          placeholder="Search..."
          onValueChange={scrollToTop}
          className={cn(
            size === 'sm' ? 'py-2' : 'py-3',
            typographyVariants({
              variant: size === 'sm' ? 'body-xs' : 'body-s',
            }),
          )}
        />
        <div className="relative">
          <CommandList
            ref={listRef}
            onScroll={handleScroll}
            style={{ maxHeight: 'calc(18rem - 2.75rem)' }}
            className={cn(
              'overflow-y-auto overscroll-contain [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
              showScrollUp && 'pt-6',
              showScrollDown && 'pb-6',
            )}
          >
            <CommandEmpty>No results found.</CommandEmpty>
            <CommandGroup>{children}</CommandGroup>
          </CommandList>
          {showScrollUp && (
            <div
              data-scroll-hint="up"
              onMouseEnter={() => startAutoScroll('up')}
              onMouseLeave={stopAutoScroll}
              onClick={() => {
                stopAutoScroll()
                listRef.current?.scrollTo({
                  top: 0,
                  behavior: 'smooth',
                })
              }}
              className="pointer-events-auto absolute inset-x-0 top-0 z-10 flex h-6 cursor-pointer items-center justify-center bg-background"
            >
              <SvgTaillessLineArrowUp1
                height={10}
                width={10}
                className="h-2.5 w-2.5 text-input-muted-foreground"
              />
            </div>
          )}
          {showScrollDown && (
            <div
              data-scroll-hint="down"
              onMouseEnter={() => startAutoScroll('down')}
              onMouseLeave={stopAutoScroll}
              onClick={() => {
                stopAutoScroll()
                listRef.current?.scrollTo({
                  top: listRef.current.scrollHeight,
                  behavior: 'smooth',
                })
              }}
              className="pointer-events-auto absolute inset-x-0 bottom-0 z-10 flex h-6 cursor-pointer items-center justify-center bg-background"
            >
              <SvgTaillessLineArrowDown1
                height={10}
                width={10}
                className="h-2.5 w-2.5 text-input-muted-foreground"
              />
            </div>
          )}
        </div>
      </Command>
    </LegacyComboboxPopoverContent>
  )
}

interface OptionRowProps {
  value: string
  children: React.ReactNode
  disabled?: boolean
  defaultValue?: boolean
  className?: string
}

export function OptionRow({
  value: optionValue,
  children,
  disabled,
  defaultValue,
  className,
}: OptionRowProps) {
  const { value, setValue, setOpen, size, setSelectedContent, clearable } =
    useLegacyComboboxContext()
  const isSelected = value === optionValue

  React.useLayoutEffect(() => {
    if (defaultValue && !value) {
      setValue(optionValue)
      setSelectedContent(children)
    }
  }, [defaultValue, value, optionValue, children, setValue, setSelectedContent])

  // Ensure selected content is in sync when value is controlled or changes externally
  React.useLayoutEffect(() => {
    if (isSelected) {
      setSelectedContent(children)
    }
  }, [isSelected, children, setSelectedContent])

  return (
    <CommandItem
      value={optionValue}
      disabled={disabled}
      onSelect={(currentValue: string) => {
        if (!clearable && currentValue === value) {
          setOpen(false)
          return
        }
        const newValue = currentValue === value ? '' : currentValue
        setValue(newValue)
        setSelectedContent(newValue ? children : null)
        setOpen(false)
      }}
      className={cn(
        typographyVariants({
          variant: size === 'default' ? 'body-s' : 'body-xs',
        }),
        'relative flex w-full cursor-default select-none items-center gap-2 px-4 py-3 outline-none',
        'text-muted-foreground',
        'data-[selected=true]:bg-accent',
        'data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50',
        '[&_svg]:text-muted-foreground',

        isSelected && '!text-brand',
        isSelected && '[&_span]:text-brand',
        isSelected && '[&_svg]:!text-brand',
        className,
      )}
    >
      <span className="absolute right-4 flex h-3.5 w-3.5 items-center justify-center">
        {isSelected && (
          <img src={getIconUrl('blocks/check')} className="h-4 w-4" alt="" />
        )}
      </span>
      {children}
    </CommandItem>
  )
}

export { LegacyComboboxIcon }
