import { useToggle } from 'ahooks'
import Fuse from 'fuse.js'
import {
  ArrowDownAZIcon,
  ArrowUpAZIcon,
  BookIcon,
  CheckIcon,
  ChevronsUpDownIcon
} from 'lucide-react'
import { forwardRef, useMemo, useState, type InputHTMLAttributes } from 'react'

import { Button } from '@repo/ui/components/ui/button'
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList
} from '@repo/ui/components/ui/command'
import {
  InputGroup,
  InputGroupAddon,
  InputGroupInput
} from '@repo/ui/components/ui/input-group'
import {
  Popover,
  PopoverContent,
  PopoverTrigger
} from '@repo/ui/components/ui/popover'
import { cn } from '@repo/ui/lib/utils'

import { Abbr } from '@repo/ui/components/abbr'
import { Kbd } from '@repo/ui/components/ui/kbd'
import { type Course } from './data'

interface CoursePickerProps extends Omit<
  InputHTMLAttributes<HTMLInputElement>,
  'value' | 'onChange'
> {
  value?: Course
  options: any[]
  onChange?: (value: any) => void
  error?: any
}

const normalize = (value: string) =>
  value
    .toLowerCase()
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .replace(/[^a-z0-9]/g, '')

export const CoursePicker = forwardRef<HTMLInputElement, CoursePickerProps>(
  ({ value, onChange, options, error, ...props }, ref) => {
    const [search, setSearch] = useState<string>('')
    const [open, { set }] = useToggle()
    const [sort, { toggle }] = useToggle('a-z', 'z-a')
    const fuse = useMemo(() => {
      return new Fuse(options, {
        keys: ['name'],
        threshold: 0.3,
        includeMatches: true,
        getFn: (obj, path) => {
          const value = obj[path as keyof typeof obj]
          return typeof value === 'string' ? normalize(value) : value
        }
      })
    }, [options])

    const filtered = useMemo(() => {
      if (!search) {
        return [...options].sort((a, b) => {
          const comparison = a.name.localeCompare(b.name)
          return sort === 'a-z' ? comparison : -comparison
        })
      }

      return fuse.search(search).map(({ item, matches }) => ({
        ...item,
        matches
      }))
    }, [search, fuse, options, sort])

    return (
      <Popover open={open} onOpenChange={set}>
        <PopoverTrigger asChild>
          <InputGroup>
            <InputGroupInput
              ref={ref}
              placeholder="Curso"
              value={value?.name || ''}
              aria-invalid={!!error}
              {...props}
            />

            <InputGroupAddon>
              <BookIcon />
            </InputGroupAddon>

            <InputGroupAddon align="inline-end">
              <ChevronsUpDownIcon />
            </InputGroupAddon>
          </InputGroup>
        </PopoverTrigger>

        <PopoverContent className="lg:w-84 p-0" align="start">
          <Command shouldFilter={false}>
            <div className="flex">
              <div className="flex-1">
                <CommandInput
                  placeholder="Digite para pesquisar"
                  autoComplete="off"
                  onValueChange={setSearch}
                />
              </div>
              <div className="border-b flex items-center justify-end">
                <Button
                  variant="link"
                  size="icon-sm"
                  tabIndex={-1}
                  className="cursor-pointer text-muted-foreground hover:text-accent-foreground"
                  onClick={toggle}
                  disabled={search.length > 0}
                >
                  {sort == 'a-z' ? <ArrowDownAZIcon /> : <ArrowUpAZIcon />}
                </Button>
              </div>
            </div>

            {/* Force rerender to reset the scroll position  */}
            <CommandList key={sort}>
              <CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>
              <CommandGroup>
                {filtered
                  .filter(
                    ({ metadata__unit_price = 0 }) => metadata__unit_price > 0
                  )
                  .map(
                    ({
                      id,
                      name,
                      access_period,
                      metadata__unit_price: unit_price,
                      quantity = null,
                      disabled = false
                    }) => {
                      return (
                        <CommandItem
                          key={id}
                          value={id}
                          className="cursor-pointer"
                          disabled={disabled}
                          onSelect={() => {
                            onChange?.({
                              id,
                              name,
                              access_period: Number(access_period),
                              unit_price: Number(unit_price)
                            })
                            set(false)
                          }}
                        >
                          <CheckIcon
                            className={cn(
                              value?.id === id ? 'opacity-100' : 'opacity-0'
                            )}
                          />
                          <Abbr>{name}</Abbr>
                          {quantity && (
                            <Kbd className="ml-auto border">{quantity}x</Kbd>
                          )}
                        </CommandItem>
                      )
                    }
                  )}
              </CommandGroup>
            </CommandList>
          </Command>
        </PopoverContent>
      </Popover>
    )
  }
)
