import {
  useEffect,
  useRef,
  useState,
  type KeyboardEvent,
} from 'react';
import { extractApiError } from '@/api/client';
import type { MitreTechnique } from '@/api/types';
import { useMitreSearch } from '@/hooks/useMitre';

interface MitreTechniquePickerProps {
  techniqueId: string | null;
  techniqueName: string | null;
  onChange: (id: string | null, name: string | null) => void;
  disabled?: boolean;
}

function formatOption(t: MitreTechnique): string {
  const tacticList = t.tactics.length > 0 ? ` (${t.tactics[0]})` : '';
  return `${t.id} — ${t.name}${tacticList}`;
}

const DEBOUNCE_MS = 200;

export function MitreTechniquePicker({
  techniqueId,
  techniqueName,
  onChange,
  disabled = false,
}: MitreTechniquePickerProps): JSX.Element {
  const [inputValue, setInputValue] = useState(
    techniqueId && techniqueName ? `${techniqueId} — ${techniqueName}` : '',
  );
  const [query, setQuery] = useState('');
  const [open, setOpen] = useState(false);
  const [activeIndex, setActiveIndex] = useState(-1);
  const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const listRef = useRef<HTMLUListElement>(null);
  // True once we've synced the first real techniqueId from props (parent/API load).
  // After that we stop reacting to null, so keystrokes that emit onChange(null,null)
  // don't propagate back and wipe the input mid-stroke.
  const hasHydratedFromProps = useRef(false);

  useEffect(() => {
    if (techniqueId && techniqueName) {
      setInputValue(`${techniqueId} — ${techniqueName}`);
      hasHydratedFromProps.current = true;
    } else if (!techniqueId && !hasHydratedFromProps.current) {
      setInputValue('');
    }
  }, [techniqueId, techniqueName]);

  const { data: results, isFetching, isError, error } = useMitreSearch(query, open);

  const items = results ?? [];

  const handleInputChange = (value: string) => {
    setInputValue(value);
    // Clear the selection when user starts typing
    onChange(null, null);
    setOpen(true);
    setActiveIndex(-1);

    if (debounceRef.current) clearTimeout(debounceRef.current);
    debounceRef.current = setTimeout(() => {
      setQuery(value);
    }, DEBOUNCE_MS);
  };

  const selectItem = (item: MitreTechnique) => {
    setInputValue(formatOption(item));
    onChange(item.id, item.name);
    setOpen(false);
    setActiveIndex(-1);
    setQuery('');
  };

  const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
    if (!open || items.length === 0) {
      if (e.key === 'Escape') setOpen(false);
      return;
    }
    if (e.key === 'ArrowDown') {
      e.preventDefault();
      setActiveIndex((i) => Math.min(i + 1, items.length - 1));
    } else if (e.key === 'ArrowUp') {
      e.preventDefault();
      setActiveIndex((i) => Math.max(i - 1, 0));
    } else if (e.key === 'Enter') {
      e.preventDefault();
      if (activeIndex >= 0 && items[activeIndex]) {
        selectItem(items[activeIndex]);
      }
    } else if (e.key === 'Escape') {
      setOpen(false);
      setActiveIndex(-1);
    }
  };

  // Scroll active item into view
  useEffect(() => {
    if (activeIndex >= 0 && listRef.current) {
      const el = listRef.current.children[activeIndex] as HTMLElement | undefined;
      el?.scrollIntoView?.({ block: 'nearest' });
    }
  }, [activeIndex]);

  // Close dropdown on click outside
  useEffect(() => {
    const onPointerDown = (e: PointerEvent) => {
      if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
        setOpen(false);
      }
    };
    document.addEventListener('pointerdown', onPointerDown);
    return () => document.removeEventListener('pointerdown', onPointerDown);
  }, []);

  const listboxId = 'mitre-picker-listbox';

  return (
    <div ref={containerRef} className="relative">
      <input
        type="text"
        role="combobox"
        aria-expanded={open}
        aria-controls={listboxId}
        aria-activedescendant={activeIndex >= 0 ? `mitre-option-${activeIndex}` : undefined}
        aria-label="MITRE technique"
        className="text-input"
        value={inputValue}
        onChange={(e) => handleInputChange(e.target.value)}
        onFocus={() => {
          if (!techniqueId) setOpen(true);
        }}
        onKeyDown={handleKeyDown}
        disabled={disabled}
        placeholder="Search by ID or name (e.g. T1059)"
        autoComplete="off"
      />

      {open && (
        <div className="absolute z-20 w-full mt-xxs bg-canvas border border-steel rounded-md shadow-floating overflow-hidden">
          {isFetching && (
            <div className="px-md py-sm text-[14px] text-graphite">Searching…</div>
          )}

          {isError && !isFetching && (
            <div className="px-md py-sm text-[14px] text-bloom-deep" role="alert">
              {extractApiError(error, 'MITRE search unavailable')}
            </div>
          )}

          {!isFetching && !isError && items.length === 0 && query.trim().length > 0 && (
            <div className="px-md py-sm text-[14px] text-graphite">No results</div>
          )}

          {!isFetching && items.length > 0 && (
            <ul
              id={listboxId}
              ref={listRef}
              role="listbox"
              aria-label="MITRE techniques"
              className="max-h-64 overflow-y-auto"
            >
              {items.map((item, i) => (
                <li
                  key={item.id}
                  id={`mitre-option-${i}`}
                  role="option"
                  aria-selected={i === activeIndex}
                  className={`px-md py-sm text-[14px] cursor-pointer select-none ${
                    i === activeIndex ? 'bg-primary-soft text-ink' : 'text-ink hover:bg-cloud'
                  }`}
                  onPointerDown={(e) => {
                    // Prevent input blur before we handle the click
                    e.preventDefault();
                    selectItem(item);
                  }}
                >
                  <span className="font-medium">{item.id}</span>
                  <span className="text-charcoal"> — {item.name}</span>
                  {item.tactics.length > 0 && (
                    <span className="text-graphite"> ({item.tactics[0]})</span>
                  )}
                </li>
              ))}
            </ul>
          )}
        </div>
      )}
    </div>
  );
}
