import React, { KeyboardEvent, useEffect, useMemo, useRef, useState } from 'react';
import { Check, ChevronDown, ChevronUp, PencilLine, Search } from 'lucide-react';

export interface ModelOption {
  value: string;
  label: string;
  provider?: string;
}

export interface ModelSelectorProps {
  id?: string;
  value: string;
  onChange: (value: string) => void;
  placeholder?: string;
  options?: ModelOption[];
  allowCustom?: boolean;
  className?: string;
  disabled?: boolean;
}

export const DEFAULT_MODEL_OPTIONS: ModelOption[] = [
  { value: 'gpt-4o', label: 'GPT-4o', provider: 'OpenAI' },
  { value: 'gpt-4o-mini', label: 'GPT-4o Mini', provider: 'OpenAI' },
  { value: 'gpt-4-turbo', label: 'GPT-4 Turbo', provider: 'OpenAI' },
  { value: 'claude-3-5-sonnet-20241022', label: 'Claude 3.5 Sonnet', provider: 'Anthropic' },
  { value: 'claude-3-opus-20240229', label: 'Claude 3 Opus', provider: 'Anthropic' },
  { value: 'glm-5.1', label: 'GLM-5.1', provider: 'Zhipu AI' },
  { value: 'gemini-2.0-flash-exp', label: 'Gemini 2.0 Flash', provider: 'Google' },
  { value: 'deepseek-chat', label: 'DeepSeek Chat', provider: 'DeepSeek' },
];

export const OLLAMA_MODEL_OPTIONS: ModelOption[] = [
  { value: 'qwen3-coder', label: 'Qwen3 Coder', provider: 'Ollama' },
  { value: 'llama3.2', label: 'Llama 3.2', provider: 'Ollama' },
  { value: 'mistral', label: 'Mistral', provider: 'Ollama' },
  { value: 'deepseek-r1', label: 'DeepSeek R1', provider: 'Ollama' },
];

export const ModelSelector: React.FC<ModelSelectorProps> = ({
  id,
  value,
  onChange,
  placeholder = 'Select or enter a model',
  options = DEFAULT_MODEL_OPTIONS,
  allowCustom = true,
  className = '',
  disabled = false,
}) => {
  const [isOpen, setIsOpen] = useState(false);
  const containerRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);

  const filteredOptions = useMemo(() => {
    const query = value.trim().toLowerCase();
    if (!query) {
      return options;
    }

    return options.filter((option) => {
      const provider = option.provider?.toLowerCase() ?? '';
      return (
        option.label.toLowerCase().includes(query) ||
        option.value.toLowerCase().includes(query) ||
        provider.includes(query)
      );
    });
  }, [options, value]);

  const selectedOption = options.find((opt) => opt.value === value);
  const trimmedValue = value.trim();
  const hasExactMatch = options.some(
    (option) => option.value.toLowerCase() === trimmedValue.toLowerCase(),
  );

  useEffect(() => {
    if (!isOpen) {
      return;
    }

    const handlePointerDown = (event: MouseEvent) => {
      if (!containerRef.current?.contains(event.target as Node)) {
        setIsOpen(false);
      }
    };

    document.addEventListener('mousedown', handlePointerDown);
    return () => document.removeEventListener('mousedown', handlePointerDown);
  }, [isOpen]);

  const handleSelect = (optionValue: string) => {
    onChange(optionValue);
    setIsOpen(false);
  };

  const handleUseCustomValue = () => {
    if (!trimmedValue) {
      return;
    }

    onChange(trimmedValue);
    setIsOpen(false);
    inputRef.current?.focus();
  };

  const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
    if (e.key === 'Enter') {
      e.preventDefault();
      if (filteredOptions.length === 1 && trimmedValue) {
        handleSelect(filteredOptions[0].value);
        return;
      }

      if (allowCustom && trimmedValue) {
        handleUseCustomValue();
        return;
      }
    }

    if (e.key === 'ArrowDown' && !isOpen) {
      e.preventDefault();
      setIsOpen(true);
    }

    if (e.key === 'Escape') {
      setIsOpen(false);
    }
  };

  return (
    <div ref={containerRef} className={`relative ${className}`}>
      <div className="relative">
        <Search className="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-term-text-tertiary" />
        <input
          id={id}
          ref={inputRef}
          type="text"
          value={value}
          onChange={(event) => {
            onChange(event.target.value);
            if (!disabled) {
              setIsOpen(true);
            }
          }}
          onFocus={() => !disabled && setIsOpen(true)}
          onKeyDown={handleKeyDown}
          placeholder={placeholder}
          disabled={disabled}
          className="w-full border border-term-border bg-term-surface py-2 pl-8 pr-11 text-sm font-mono text-term-text outline-none transition-all hover:border-term-border-focus focus:border-info disabled:cursor-not-allowed disabled:opacity-50 border-l-2 focus:border-l-info hover:border-l-term-border-focus"
          aria-haspopup="listbox"
          aria-expanded={isOpen}
          aria-autocomplete="list"
        />
        <button
          type="button"
          onMouseDown={(event) => event.preventDefault()}
          onClick={() => {
            if (!disabled) {
              setIsOpen((current) => !current);
              inputRef.current?.focus();
            }
          }}
          disabled={disabled}
          className="absolute right-2 top-1/2 -translate-y-1/2 text-term-text-tertiary transition-colors hover:text-term-text disabled:cursor-not-allowed disabled:opacity-50"
          aria-label={isOpen ? 'Hide model suggestions' : 'Show model suggestions'}
        >
          {isOpen ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />}
        </button>
      </div>

      <div className="mt-1 flex items-center justify-between gap-3 text-[11px] font-mono text-term-text-tertiary">
        <span className="truncate">
          {selectedOption
            ? `${selectedOption.label}${selectedOption.provider ? ` · ${selectedOption.provider}` : ''}`
            : trimmedValue
              ? 'Custom model name'
              : 'Type an exact model name or pick a suggestion'}
        </span>
        {allowCustom && trimmedValue && !hasExactMatch && (
          <button
            type="button"
            onMouseDown={(event) => event.preventDefault()}
            onClick={handleUseCustomValue}
            className="inline-flex flex-shrink-0 items-center gap-1 text-info transition-colors hover:text-term-text"
          >
            <PencilLine className="h-3 w-3" />
            Use custom
          </button>
        )}
      </div>

      {isOpen && (
        <div className="absolute z-10 mt-1 max-h-60 w-full overflow-auto border border-term-border bg-term-surface shadow-lg">
          <ul role="listbox" className="py-1">
            {allowCustom && trimmedValue && !hasExactMatch && (
              <>
                <li
                  role="option"
                  aria-selected={false}
                  onMouseDown={(event) => event.preventDefault()}
                  onClick={handleUseCustomValue}
                  className="cursor-pointer px-3 py-2 text-sm font-mono text-info transition-colors hover:bg-term-highlight"
                >
                  <div className="flex items-center justify-between gap-3">
                    <span className="truncate">Use "{trimmedValue}" as a custom model</span>
                    <PencilLine className="h-3.5 w-3.5 flex-shrink-0" />
                  </div>
                </li>
                <li className="my-1 border-t border-term-border-subtle" role="separator" />
              </>
            )}
            {filteredOptions.length === 0 ? (
              <li className="px-3 py-4 text-center">
                <div className="flex items-center justify-center gap-2 text-xs font-mono text-term-text-tertiary">
                  <div className="h-px w-8 bg-term-border" />
                  <span>{trimmedValue ? 'No preset matches' : 'No models found'}</span>
                  <div className="h-px w-8 bg-term-border" />
                </div>
              </li>
            ) : (
              filteredOptions.map((option) => (
                <li
                  key={option.value}
                  role="option"
                  aria-selected={value === option.value}
                  onMouseDown={(event) => event.preventDefault()}
                  onClick={() => handleSelect(option.value)}
                  className={`cursor-pointer px-3 py-2 text-sm font-mono transition-colors border-l-2 ${
                    value === option.value
                      ? 'border-l-info bg-[var(--term-status-info)] text-[var(--term-status-info-strong)]'
                      : 'border-l-transparent text-term-text hover:border-l-term-border hover:bg-term-highlight'
                  }`}
                >
                  <div className="flex items-center justify-between">
                    <div className="min-w-0">
                      <div className="truncate">{option.label}</div>
                      <div className="truncate text-xs text-term-text-tertiary">{option.value}</div>
                    </div>
                    <div className="ml-2 flex items-center gap-2">
                      {option.provider && (
                        <span className="text-xs text-term-text-tertiary">{option.provider}</span>
                      )}
                      {value === option.value && <Check className="h-3.5 w-3.5 text-info" />}
                    </div>
                  </div>
                </li>
              ))
            )}
          </ul>
        </div>
      )}
    </div>
  );
};
