'use client';

import { useEffect, useRef, useState } from 'react';
import clsx from 'clsx';
import { ChevronDownIcon } from 'lucide-react';

import { IconRemove } from '../icons';
import { type Styling } from '../props';
import { cn } from '../utils';

import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from './command';
import { Popover, PopoverContent, PopoverTrigger } from './popover';

interface ComboMultiProps<Option> extends Styling {
  id?: string;
  items?: Option[];
  value: Option[];
  onChange: (newValue: Option[]) => void;

  idFunc: (item: Option) => string;
  labelValueFunc: (item: Option) => string;
  labelOptionFunc: (item: Option) => string;

  placeholder?: string;
  noSearch?: boolean;
}

/**
 * Displays a combo-box component with multiple selection.
 */
export function ComboMulti<Option>({
  id,
  items,
  value,
  onChange,
  labelValueFunc,
  labelOptionFunc,
  idFunc,
  placeholder,
  className,
  style,
  noSearch
}: ComboMultiProps<Option>) {
  const [open, setOpen] = useState(false);
  const [popoverWidth, setPopoverWidth] = useState<number | undefined>(undefined);
  const triggerRef = useRef<HTMLButtonElement>(null);

  useEffect(() => {
    if (triggerRef.current) {
      setPopoverWidth(triggerRef.current.offsetWidth);
    }
  }, [open]);

  function handleAddValue(newValue: Option) {
    if (value.includes(newValue)) {
      handleRemoveValue(newValue);
    } else {
      onChange([...value, newValue]);
      setOpen(false);
    }
  }

  function handleRemoveValue(delValue: Option) {
    onChange(value.filter(v => v !== delValue));
    setOpen(false);
  }

  function handleClear(event: React.MouseEvent<SVGElement>) {
    event.stopPropagation();
    onChange([]);
    setOpen(false);
  }

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <button
          id={id}
          ref={triggerRef}
          role='combobox'
          aria-expanded={open}
          className={cn(
            'relative h-9',
            'flex gap-2 px-3 py-2 items-center justify-between',
            'bg-input disabled:opacity-50',
            'cursor-pointer disabled:cursor-auto',
            'whitespace-nowrap',
            'focus-outline border',
            "[&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0",
            open && 'cursor-auto',
            !value && 'text-muted-foreground',
            className
          )}
          style={style}
        >
          <div className='flex flex-wrap items-center'>
            {value.length === 0 ? <div className='text-muted-foreground'>{placeholder}</div> : null}
            {value.map(item => (
              <div
                key={idFunc(item)}
                className={clsx('m-1', 'flex px-1 items-center', 'border rounded-lg', 'bg-accent', 'text-sm')}
              >
                {labelValueFunc(item)}
                <IconRemove
                  tabIndex={-1}
                  size='1rem'
                  className='text-muted-foreground hover:text-destructive'
                  onClick={event => {
                    event.stopPropagation();
                    handleRemoveValue(item);
                  }}
                />
              </div>
            ))}
          </div>

          <ChevronDownIcon className={cn('text-muted-foreground', !!value && 'opacity-0')} />
          {!!value ? (
            <IconRemove
              tabIndex={-1}
              size='1rem'
              className='absolute pointer-events-auto right-3 text-muted-foreground hover:text-destructive'
              onClick={handleClear}
            />
          ) : null}
        </button>
      </PopoverTrigger>
      <PopoverContent sideOffset={-1} className='p-0' style={{ width: popoverWidth }}>
        <Command>
          {!noSearch ? <CommandInput placeholder='Поиск...' className='h-9' /> : null}
          <CommandList>
            <CommandEmpty>Список пуст</CommandEmpty>
            <CommandGroup>
              {items?.map(item => (
                <CommandItem
                  key={idFunc(item)}
                  value={labelOptionFunc(item)}
                  onSelect={() => handleAddValue(item)}
                  className={cn(value === item && 'bg-selected text-selected-foreground')}
                >
                  {labelOptionFunc(item)}
                </CommandItem>
              ))}
            </CommandGroup>
          </CommandList>
        </Command>
      </PopoverContent>
    </Popover>
  );
}
