'use client';

import {
  type KeyboardEventHandler,
  type ReactNode,
  useEffect,
  useId,
  useMemo,
  useRef,
  useState,
} from 'react';

import { ChevronDown, Search } from 'lucide-react';
import { createPortal } from 'react-dom';
import type { VirtuosoHandle } from 'react-virtuoso';

import CreatorDeathMark from '@/components/creators/CreatorDeathMark';
import CreatorResultList from '@/components/creators/CreatorResultList';
import { useFloatingDropdown } from '@/hooks/useFloatingDropdown';
import { cn } from '@/lib/utils';
import { creatorIdentityMatchesQuery } from '@/utils/creatorIdentity';

import type { CreatorIdentity } from '@/types/Creator';

interface CreatorComboboxProps<TCreator extends CreatorIdentity> {
  options: TCreator[];
  onSelect: (creator: TCreator) => void;
  placeholder: string;
  ariaLabel: string;
  value?: string | null;
  variant?: 'default' | 'inline';
  emptyLabel?: ReactNode;
  disabledCreatorId?: string | null;
  className?: string;
}

const CreatorCombobox = <TCreator extends CreatorIdentity>({
  options,
  onSelect,
  placeholder,
  ariaLabel,
  value = null,
  variant = 'default',
  emptyLabel = placeholder,
  disabledCreatorId = null,
  className,
}: CreatorComboboxProps<TCreator>) => {
  const inputId = useId();
  const listboxId = useId();
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState('');
  const [activeIndex, setActiveIndex] = useState(-1);
  const inputRef = useRef<HTMLInputElement | null>(null);
  const virtuosoRef = useRef<VirtuosoHandle | null>(null);
  const {
    anchorRef,
    dropdownRef,
    layout: dropdownLayout,
  } = useFloatingDropdown({
    open,
    onOpenChange: setOpen,
    minWidth: variant === 'inline' ? 280 : 0,
    minHeight: 220,
    maxHeight: 420,
  });
  const isInline = variant === 'inline';

  const selectedCreator = useMemo(
    () => (value ? options.find((creator) => creator.alkotoAzonosito === value) || null : null),
    [options, value]
  );
  const selectedProfession = selectedCreator?.szakma?.trim() || '';
  const showInlineDeathMark = isInline && !query && Boolean(selectedCreator?.elhalalozasIdeje);
  const showInlineProfession = isInline && !query && Boolean(selectedProfession);
  const filteredCreators = useMemo(
    () => options.filter((creator) => creatorIdentityMatchesQuery(creator, query)),
    [options, query]
  );
  const selectedIndex = useMemo(
    () => (value ? filteredCreators.findIndex((creator) => creator.alkotoAzonosito === value) : -1),
    [filteredCreators, value]
  );

  useEffect(() => {
    if (filteredCreators.length === 0) {
      setActiveIndex(-1);
      return;
    }

    setActiveIndex(selectedIndex >= 0 ? selectedIndex : 0);
  }, [filteredCreators.length, query, selectedIndex]);

  useEffect(() => {
    if (!open || activeIndex < 0 || !virtuosoRef.current) return;

    virtuosoRef.current.scrollToIndex({
      index: activeIndex,
      align: 'center',
      behavior: 'auto',
    });
  }, [activeIndex, open]);

  const selectCreator = (creator: TCreator) => {
    onSelect(creator);
    setQuery('');
    setOpen(false);
  };

  const handleKeyDown: KeyboardEventHandler<HTMLInputElement> = (event) => {
    if (!open && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {
      if (!filteredCreators.length) return;
      event.preventDefault();
      setOpen(true);
      return;
    }

    if (event.key === 'ArrowDown') {
      event.preventDefault();
      if (!filteredCreators.length) return;
      setActiveIndex((previous) => Math.min(previous + 1, filteredCreators.length - 1));
      return;
    }

    if (event.key === 'ArrowUp') {
      event.preventDefault();
      if (!filteredCreators.length) return;
      setActiveIndex((previous) => Math.max(previous - 1, 0));
      return;
    }

    if (event.key === 'Enter') {
      if (!open) return;
      event.preventDefault();
      if (activeIndex < 0 || activeIndex >= filteredCreators.length) return;

      const creator = filteredCreators[activeIndex];
      if (!creator || disabledCreatorId === creator.alkotoAzonosito) return;
      selectCreator(creator);
      return;
    }

    if (event.key === 'Escape') {
      setOpen(false);
    }
  };

  const activeOptionId =
    open && activeIndex >= 0 && activeIndex < filteredCreators.length
      ? `${listboxId}-option-${activeIndex}`
      : undefined;
  const inlineDisplayName = selectedCreator?.nev || placeholder;
  const showInlineDisplay = isInline && !query;

  const input = (
    <input
      ref={inputRef}
      id={inputId}
      type="text"
      value={query}
      onChange={(event) => {
        setQuery(event.target.value);
        setOpen(true);
      }}
      onFocus={() => setOpen(true)}
      onClick={() => setOpen(true)}
      onKeyDown={handleKeyDown}
      placeholder={
        showInlineDisplay ? '' : query ? placeholder : selectedCreator?.nev || placeholder
      }
      role="combobox"
      aria-label={ariaLabel}
      aria-expanded={open}
      aria-haspopup="listbox"
      aria-controls={listboxId}
      aria-autocomplete="list"
      aria-activedescendant={activeOptionId}
      className={cn(
        'min-w-0 bg-transparent font-semibold text-[#151720] outline-none',
        isInline
          ? [
              'text-center text-[13px] leading-tight placeholder:text-[#151720]',
              showInlineDisplay
                ? 'absolute inset-0 h-full w-full cursor-pointer opacity-0 caret-transparent'
                : 'h-5 w-full cursor-text',
            ]
          : 'flex-1 text-sm placeholder:text-[#151720]/55'
      )}
    />
  );

  return (
    <div ref={anchorRef} className={cn('relative w-full', className)}>
      <label htmlFor={inputId} className="sr-only">
        {ariaLabel}
      </label>
      <div
        onClick={() => {
          if (!isInline) return;
          inputRef.current?.focus();
          setOpen(true);
        }}
        className={cn(
          'group relative w-full overflow-hidden border border-[#151720]/18 bg-white transition hover:border-[#151720]/28 focus-within:ring-1 focus-within:ring-[#151720]/25',
          isInline
            ? 'grid h-14 cursor-pointer grid-cols-[1rem_minmax(0,1fr)_1rem] items-center gap-2 rounded-none px-3 text-center shadow-none'
            : 'flex h-14 items-center gap-3 rounded-none px-4 text-left shadow-[0_18px_42px_-28px_rgba(15,23,42,0.8)]'
        )}
      >
        {isInline ? (
          <>
            <span className="h-4 w-4" aria-hidden />
            <div className="relative min-w-0 py-1.5 text-center">
              {showInlineDisplay ? (
                <div className="pointer-events-none flex min-w-0 items-center justify-center gap-1">
                  {showInlineDeathMark ? (
                    <CreatorDeathMark className="shrink-0 text-[11px] text-[#151720]/65" />
                  ) : null}
                  <span className="min-w-0 truncate text-[13px] font-semibold leading-tight text-[#151720]">
                    {inlineDisplayName}
                  </span>
                </div>
              ) : (
                <div className="flex min-w-0 items-center justify-center">{input}</div>
              )}
              {showInlineProfession ? (
                <p
                  className="mt-0.5 truncate text-center text-[11px] font-semibold leading-tight text-[#151720]/65"
                  title={selectedProfession}
                >
                  {selectedProfession}
                </p>
              ) : null}
              {showInlineDisplay ? input : null}
            </div>
          </>
        ) : (
          <>
            <Search size={18} className="shrink-0 text-[#151720]/50" />
            {input}
          </>
        )}
        <button
          type="button"
          onClick={(event) => {
            event.stopPropagation();
            setOpen((previous) => !previous);
          }}
          aria-label={ariaLabel}
          aria-expanded={open}
          aria-controls={listboxId}
          className={cn(
            'shrink-0 text-[#151720]/55',
            isInline && 'cursor-pointer justify-self-end'
          )}
        >
          <ChevronDown size={16} className={cn('transition-transform', open && 'rotate-180')} />
        </button>
      </div>

      {open && dropdownLayout
        ? createPortal(
            <div
              ref={dropdownRef}
              id={listboxId}
              role="listbox"
              style={{
                position: 'fixed',
                top: dropdownLayout.top,
                left: dropdownLayout.left,
                width: dropdownLayout.width,
              }}
              className={cn(
                'z-[4000] overflow-hidden border border-[#151720]/12 bg-white p-1 shadow-[0_18px_42px_-24px_rgba(15,23,42,0.85)]',
                'rounded-none'
              )}
            >
              <CreatorResultList
                creators={filteredCreators}
                emptyLabel={emptyLabel}
                onSelect={selectCreator}
                activeIndex={activeIndex}
                getOptionId={(index) => `${listboxId}-option-${index}`}
                isDisabled={(creator) => disabledCreatorId === creator.alkotoAzonosito}
                isSelected={(creator) => Boolean(value) && creator.alkotoAzonosito === value}
                itemClassName={({ active, selected, disabled }) =>
                  cn(
                    'rounded-none py-2',
                    active && 'bg-[#f3f6f9]',
                    selected && !active && 'bg-[#f7f7f8]',
                    !active && !selected && !disabled && 'hover:bg-[#f7f9fb]'
                  )
                }
                preventMouseDown
                virtualized
                virtuosoRef={virtuosoRef}
                height={dropdownLayout.height}
              />
            </div>,
            document.body
          )
        : null}
    </div>
  );
};

export default CreatorCombobox;
