'use client';

/* ════════════════════════════ SearchBar ════════════════════════════
 *
 * Reusable search bar met debounce, resultaten dropdown, en toetsenbordnavigatie.
 * Gebruikt de client-side search index (search-index.ts) of een custom onSearch callback.
 */

import { useState, useRef, useEffect, useCallback } from 'react';
import { Search, X, FileIcon, FolderIcon, Loader2 } from 'lucide-react';
import { searchIndex, type SearchResult } from '@/lib/search-index';

/* ════════════════════════════ Types ════════════════════════════ */

export interface SearchBarProps {
  /** External search handler (optioneel — gebruikt search-index.ts anders) */
  onSearch?: (query: string) => Promise<SearchResult[]> | SearchResult[];
  /** Called when user selects a result */
  onSelect: (result: SearchResult) => void;
  /** Placeholder text */
  placeholder?: string;
  /** Auto-focus on mount */
  autoFocus?: boolean;
  /** Extra CSS classes */
  className?: string;
}

/* ════════════════════════════ Component ════════════════════════════ */

export default function SearchBar({
  onSearch,
  onSelect,
  placeholder = 'Search files, CIDs, and content…',
  autoFocus = false,
  className = '',
}: SearchBarProps) {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState<SearchResult[]>([]);
  const [loading, setLoading] = useState(false);
  const [showResults, setShowResults] = useState(false);
  const [selectedIdx, setSelectedIdx] = useState(-1);

  const inputRef = useRef<HTMLInputElement>(null);
  const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const panelRef = useRef<HTMLDivElement>(null);

  /* ── Search logic ── */

  const doSearch = useCallback(async (q: string) => {
    if (!q || q.trim().length < 2) {
      setResults([]);
      setShowResults(false);
      return;
    }

    setLoading(true);
    try {
      const hits = onSearch
        ? await onSearch(q)
        : searchIndex(q);
      setResults(hits);
      setShowResults(true);
      setSelectedIdx(-1);
    } finally {
      setLoading(false);
    }
  }, [onSearch]);

  /* ── Debounced input ── */

  function handleChange(value: string) {
    setQuery(value);
    if (debounceRef.current) clearTimeout(debounceRef.current);
    debounceRef.current = setTimeout(() => doSearch(value), 250);
  }

  /* ── Keyboard navigation ── */

  function handleKeyDown(e: React.KeyboardEvent) {
    if (!showResults || results.length === 0) return;

    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault();
        setSelectedIdx((prev) => Math.min(prev + 1, results.length - 1));
        break;
      case 'ArrowUp':
        e.preventDefault();
        setSelectedIdx((prev) => Math.max(prev - 1, 0));
        break;
      case 'Enter':
        e.preventDefault();
        if (selectedIdx >= 0 && selectedIdx < results.length) {
          handleSelect(results[selectedIdx]);
        }
        break;
      case 'Escape':
        setShowResults(false);
        inputRef.current?.blur();
        break;
    }
  }

  /* ── Select ── */

  function handleSelect(result: SearchResult) {
    setShowResults(false);
    setQuery('');
    onSelect(result);
  }

  /* ── Click outside ── */

  useEffect(() => {
    function handleClick(e: MouseEvent) {
      if (panelRef.current && !panelRef.current.contains(e.target as Node)) {
        setShowResults(false);
      }
    }
    document.addEventListener('mousedown', handleClick);
    return () => document.removeEventListener('mousedown', handleClick);
  }, []);

  /* ── Cleanup ── */

  useEffect(() => {
    if (autoFocus) inputRef.current?.focus();
    return () => {
      if (debounceRef.current) clearTimeout(debounceRef.current);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  /* ════════════════════════════ Render ════════════════════════════ */

  return (
    <div ref={panelRef} className={`relative ${className}`}>
      {/* Input */}
      <div className="relative">
        <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-surface-500 pointer-events-none" />
        <input
          ref={inputRef}
          value={query}
          onChange={(e) => handleChange(e.target.value)}
          onKeyDown={handleKeyDown}
          onFocus={() => { if (results.length > 0) setShowResults(true); }}
          placeholder={placeholder}
          className="w-full pl-10 pr-10 py-2.5 rounded-xl bg-surface-900 border border-surface-700 text-sm text-surface-200 placeholder:text-surface-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-500/50 focus-visible:border-brand-500 transition-colors"
          autoFocus={autoFocus}
          role="combobox"
          aria-expanded={showResults}
          aria-haspopup="listbox"
          aria-autocomplete="list"
          aria-controls="search-results-listbox"
        />
        {loading && (
          <Loader2 className="absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-surface-500 animate-spin" />
        )}
        {!loading && query && (
          <button
            onClick={() => { setQuery(''); setResults([]); setShowResults(false); inputRef.current?.focus(); }}
            className="absolute right-3 top-1/2 -translate-y-1/2 p-0.5 rounded hover:bg-surface-700 transition-colors"
          >
            <X className="w-4 h-4 text-surface-500" />
          </button>
        )}
      </div>

      {/* Live region for screen readers */}
      <div aria-live="polite" aria-atomic="true" className="sr-only">
        {showResults ? `${results.length} resultaten` : ''}
      </div>

      {/* Results dropdown */}
      {showResults && (
        <div
          id="search-results-listbox"
          role="listbox"
          className="absolute top-full left-0 right-0 mt-2 glass rounded-xl overflow-hidden shadow-xl z-50 max-h-72 overflow-y-auto animate-fade-in">
          {results.length === 0 && !loading ? (
            <div className="p-4 text-sm text-surface-500 text-center">No results found</div>
          ) : (
            results.map((result, idx) => (
              <button
                key={result.entry.cid + result.matchField}
                id={`search-result-${idx}`}
                role="option"
                aria-selected={idx === selectedIdx}
                onClick={() => handleSelect(result)}
                onMouseEnter={() => setSelectedIdx(idx)}
                className={`w-full flex items-start gap-3 px-4 py-3 text-left text-sm transition-colors ${
                  idx === selectedIdx ? 'bg-surface-700/50' : 'hover:bg-surface-800/50'
                }`}
              >
                {result.entry.type === 'dir'
                  ? <FolderIcon className="w-4 h-4 text-accent-amber shrink-0 mt-0.5" />
                  : <FileIcon className="w-4 h-4 text-accent-blue shrink-0 mt-0.5" />
                }
                <div className="flex-1 min-w-0">
                  <div className="flex items-center gap-2">
                    <span className="text-surface-200 font-medium truncate">
                      {result.entry.name || result.entry.cid.slice(0, 20) + '…'}
                    </span>
                    {result.matchField === 'name' && (
                      <span className="text-[10px] text-brand-400 bg-brand-500/10 px-1.5 py-0.5 rounded-full shrink-0">Name</span>
                    )}
                    {result.matchField === 'cid' && (
                      <span className="text-[10px] text-accent-cyan bg-accent-cyan/10 px-1.5 py-0.5 rounded-full shrink-0">CID</span>
                    )}
                  </div>
                  {result.entry.text && (
                    <p className="text-xs text-surface-500 mt-0.5 line-clamp-1">
                      {result.entry.text.slice(0, 120)}
                    </p>
                  )}
                  <p className="text-[11px] text-surface-600 font-mono mt-0.5">
                    {result.entry.cid.slice(0, 16)}…
                  </p>
                </div>
                <span className="text-[11px] text-surface-500 shrink-0">
                  {result.entry.size > 0
                    ? result.entry.size < 1024
                      ? `${result.entry.size} B`
                      : `${(result.entry.size / 1024).toFixed(1)} KB`
                    : ''}
                </span>
              </button>
            ))
          )}
        </div>
      )}
    </div>
  );
}
