import { useCallback, useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { DITHERED_SHADOW } from "@/components/shared/FloatingWindow";
import type { NetworkNode } from "@/api/client";

interface BrowseSearchBarProps {
  filter: string;
  onFilterChange: (value: string) => void;
  onClear: () => void;
  allNodes: NetworkNode[];
  suggestions: NetworkNode[];
  onSelectNode: (node: NetworkNode) => void;
  onHighlightNode: (node: NetworkNode | null) => void;
  onSearchFocusChange: (focused: boolean) => void;
  focusedWinId: string | null;
  windowCount: number;
}

export default function BrowseSearchBar({
  filter, onFilterChange, onClear,
  allNodes, suggestions, onSelectNode, onHighlightNode, onSearchFocusChange,
  focusedWinId, windowCount,
}: BrowseSearchBarProps) {
  const searchInputRef = useRef<HTMLInputElement>(null);
  const [selectedSuggestion, setSelectedSuggestion] = useState(-1);
  const [focused, setFocused] = useState(false);

  // The visible list: when focused with no filter, show all nodes; otherwise filtered suggestions
  const visibleList = focused && !filter.trim() ? allNodes : suggestions;
  const maxVisible = 12;
  const displayList = visibleList.slice(0, maxVisible);
  const hasMore = visibleList.length > maxVisible;

  // Reset selection when list changes
  useEffect(() => { setSelectedSuggestion(-1); }, [visibleList.length, filter]);

  // Notify parent of highlight changes for camera fly-to
  useEffect(() => {
    const entry = selectedSuggestion >= 0 ? displayList[selectedSuggestion] : null;
    onHighlightNode(entry ?? null);
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectedSuggestion, onHighlightNode]);

  // Auto-focus search when no windows open
  useEffect(() => { searchInputRef.current?.focus(); }, []);
  useEffect(() => {
    if (windowCount === 0) searchInputRef.current?.focus();
  }, [windowCount]);

  // Capture typing into search when no window is focused
  useEffect(() => {
    const onKeyDown = (e: KeyboardEvent) => {
      if (focusedWinId) return;
      if (document.activeElement === searchInputRef.current) return;
      if (e.metaKey || e.ctrlKey || e.altKey) return;
      if (e.key.length !== 1) return;
      searchInputRef.current?.focus();
    };
    document.addEventListener("keydown", onKeyDown);
    return () => document.removeEventListener("keydown", onKeyDown);
  }, [focusedWinId]);

  const handleFocus = useCallback(() => {
    setFocused(true);
    onSearchFocusChange(true);
  }, [onSearchFocusChange]);

  const handleBlur = useCallback(() => {
    // Delay to allow click on suggestion to fire before closing
    setTimeout(() => {
      setFocused(false);
      onSearchFocusChange(false);
      setSelectedSuggestion(-1);
    }, 150);
  }, [onSearchFocusChange]);

  // Draggable position
  const [searchPos, setSearchPos] = useState<{ x: number; y: number } | null>(null);
  const searchDragRef = useRef<{ startX: number; startY: number; origX: number; origY: number } | null>(null);
  useEffect(() => { setSearchPos({ x: Math.round(window.innerWidth / 2 - 200), y: window.innerHeight - 307 }); }, []);

  const onSearchDragStart = useCallback((e: React.MouseEvent) => {
    if ((e.target as HTMLElement).tagName === "INPUT") return;
    e.preventDefault();
    const pos = searchPos ?? { x: 0, y: 0 };
    searchDragRef.current = { startX: e.clientX, startY: e.clientY, origX: pos.x, origY: pos.y };
    const onMove = (ev: MouseEvent) => { if (!searchDragRef.current) return; setSearchPos({ x: searchDragRef.current.origX + (ev.clientX - searchDragRef.current.startX), y: Math.max(0, searchDragRef.current.origY + (ev.clientY - searchDragRef.current.startY)) }); };
    const onUp = () => { searchDragRef.current = null; document.removeEventListener("mousemove", onMove); document.removeEventListener("mouseup", onUp); };
    document.addEventListener("mousemove", onMove); document.addEventListener("mouseup", onUp);
  }, [searchPos]);

  if (!searchPos) return null;

  const showDropdown = focused && displayList.length > 0;

  return createPortal(
    <div onMouseDown={onSearchDragStart}
      className="fixed z-999 flex flex-col bg-popover border-2 border-border focus-within:border-primary rounded-lg cursor-grab active:cursor-grabbing transition-[border-color] duration-150"
      style={{ left: searchPos.x, top: searchPos.y, width: 400, boxShadow: DITHERED_SHADOW }}>
      <div className="flex items-center gap-3 px-3 py-1.5">
        <input ref={searchInputRef} type="text" value={filter}
          onChange={(e) => onFilterChange(e.target.value)}
          onFocus={handleFocus}
          onBlur={handleBlur}
          onKeyDown={(e) => {
            if (e.key === "Escape") { onClear(); e.currentTarget.blur(); return; }
            if (e.key === "ArrowDown") { e.preventDefault(); setSelectedSuggestion(i => Math.min(i + 1, displayList.length - 1)); return; }
            if (e.key === "ArrowUp") { e.preventDefault(); setSelectedSuggestion(i => Math.max(i - 1, -1)); return; }
            if (e.key === "Enter") {
              e.preventDefault();
              const entry = selectedSuggestion >= 0 ? displayList[selectedSuggestion] : displayList[0];
              if (entry && entry.type !== "interface") { onSelectNode(entry); onClear(); }
              return;
            }
          }}
          placeholder="Search nodes..."
          className="flex-1 h-7 px-2 text-xs bg-background/60 border border-border rounded placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-primary cursor-text" />
        {filter && (
          <button onClick={onClear} className="text-muted-foreground hover:text-foreground transition-colors text-xs leading-none px-1" title="Clear search (Esc)">
            &times;
          </button>
        )}
        {!filter && focused && (
          <span className="text-[9px] text-muted-foreground uppercase tracking-wider shrink-0">
            {allNodes.length} nodes
          </span>
        )}
      </div>
      {showDropdown && (
        <div className="border-t border-border max-h-[360px] overflow-y-auto">
          {displayList.map((entry, i) => (
            <button
              key={entry.hash}
              onMouseDown={(e) => { e.preventDefault(); if (entry.type !== "interface") { onSelectNode(entry); onClear(); } }}
              onMouseEnter={() => setSelectedSuggestion(i)}
              className={`w-full text-left px-3 py-1.5 text-xs font-mono flex items-center gap-2 transition-colors ${i === selectedSuggestion ? "bg-accent text-accent-foreground" : "text-foreground hover:bg-accent/50"
                }`}
            >
              <span className="w-2 h-2 rounded-full shrink-0" style={{
                backgroundColor: (() => {
                  const age = Date.now() / 1000 - (entry.last_seen ?? 0);
                  if (age < 300) return "var(--primary)";
                  if (age < 3600) return "var(--muted-foreground)";
                  return "var(--border)";
                })(),
              }} />
              <span className="truncate">{entry.name}</span>
              <span className="ml-auto text-[9px] text-muted-foreground uppercase shrink-0">
                {entry.interface ?? "peer"}
              </span>
            </button>
          ))}
          {hasMore && (
            <div className="px-3 py-1 text-[9px] text-muted-foreground text-center border-t border-border/50">
              {visibleList.length - maxVisible} more — type to narrow
            </div>
          )}
        </div>
      )}
    </div>, document.body);
}
