'use client';

import * as React from 'react';
import { cn } from '@/lib/utils';

/* -------------------------------------------------------------------------- */
/*  Command Palette (Cmd+K / Ctrl+K style)                                    */
/*  A search overlay with filterable list of commands/actions.                */
/* -------------------------------------------------------------------------- */

export interface Command {
  /** Unique identifier */
  id: string;
  /** Display label */
  label: string;
  /** Optional grouping category */
  category?: string;
  /** Optional keyboard shortcut hint (e.g. "Cmd+1") */
  shortcut?: string;
  /** Optional icon element rendered before the label */
  icon?: React.ReactNode;
  /** Whether the command is disabled */
  disabled?: boolean;
}

export interface CommandPaletteProps {
  /** Controls visibility */
  open: boolean;
  /** Called when the palette wants to close */
  onClose: () => void;
  /** Array of available commands */
  commands: Command[];
  /** Called when a command is selected */
  onSelect: (command: Command) => void;
  /** Placeholder text for the search input */
  placeholder?: string;
  /** Additional class names for the outer container */
  className?: string;
}

export function CommandPalette({
  open,
  onClose,
  commands,
  onSelect,
  placeholder = 'Type a command or search...',
  className,
}: CommandPaletteProps) {
  const [query, setQuery] = React.useState('');
  const [activeIndex, setActiveIndex] = React.useState(0);
  const inputRef = React.useRef<HTMLInputElement>(null);
  const listRef = React.useRef<HTMLDivElement>(null);

  /* -- Filter commands by query -- */
  const filtered = React.useMemo(() => {
    if (!query.trim()) return commands.filter((c) => !c.disabled);
    const lower = query.toLowerCase();
    return commands.filter(
      (c) =>
        !c.disabled &&
        (c.label.toLowerCase().includes(lower) ||
          c.category?.toLowerCase().includes(lower)),
    );
  }, [commands, query]);

  /* -- Group by category -- */
  const grouped = React.useMemo(() => {
    const map = new Map<string, Command[]>();
    for (const cmd of filtered) {
      const cat = cmd.category ?? '';
      if (!map.has(cat)) map.set(cat, []);
      map.get(cat)!.push(cmd);
    }
    return map;
  }, [filtered]);

  /* -- Reset on open/close -- */
  React.useEffect(() => {
    if (open) {
      setQuery('');
      setActiveIndex(0);
      // Focus input after the portal renders
      requestAnimationFrame(() => inputRef.current?.focus());
    }
  }, [open]);

  /* -- Clamp active index when filtered list changes -- */
  React.useEffect(() => {
    setActiveIndex((prev) => Math.min(prev, Math.max(filtered.length - 1, 0)));
  }, [filtered.length]);

  /* -- Scroll active item into view -- */
  React.useEffect(() => {
    const active = listRef.current?.querySelector('[data-active="true"]');
    active?.scrollIntoView({ block: 'nearest' });
  }, [activeIndex]);

  /* -- Keyboard navigation -- */
  const handleKeyDown = React.useCallback(
    (e: React.KeyboardEvent) => {
      switch (e.key) {
        case 'ArrowDown':
          e.preventDefault();
          setActiveIndex((i) => (i + 1) % (filtered.length || 1));
          break;
        case 'ArrowUp':
          e.preventDefault();
          setActiveIndex((i) => (i - 1 + (filtered.length || 1)) % (filtered.length || 1));
          break;
        case 'Enter':
          e.preventDefault();
          if (filtered[activeIndex]) {
            onSelect(filtered[activeIndex]);
            onClose();
          }
          break;
        case 'Escape':
          e.preventDefault();
          onClose();
          break;
      }
    },
    [filtered, activeIndex, onSelect, onClose],
  );

  if (!open) return null;

  let flatIndex = 0;

  return (
    /* Backdrop */
    <div
      className="fixed inset-0 z-50 flex items-start justify-center pt-[20vh]"
      onClick={onClose}
      role="presentation"
    >
      {/* Overlay */}
      <div className="fixed inset-0 bg-black/50 backdrop-blur-sm" aria-hidden />

      {/* Panel */}
      <div
        className={cn(
          'relative z-50 w-full max-w-lg overflow-hidden rounded-lg border bg-background shadow-2xl',
          'animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 duration-150',
          className,
        )}
        onClick={(e) => e.stopPropagation()}
        role="dialog"
        aria-modal="true"
        aria-label="Command palette"
        onKeyDown={handleKeyDown}
      >
        {/* Search Input */}
        <div className="flex items-center border-b px-3">
          <svg
            className="mr-2 h-4 w-4 shrink-0 text-muted-foreground"
            xmlns="http://www.w3.org/2000/svg"
            fill="none"
            viewBox="0 0 24 24"
            stroke="currentColor"
            strokeWidth="2"
          >
            <circle cx="11" cy="11" r="8" />
            <path d="m21 21-4.3-4.3" />
          </svg>
          <input
            ref={inputRef}
            type="text"
            className="flex h-11 w-full bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
            placeholder={placeholder}
            value={query}
            onChange={(e) => {
              setQuery(e.target.value);
              setActiveIndex(0);
            }}
          />
          <kbd className="ml-2 hidden rounded border bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground sm:inline">
            ESC
          </kbd>
        </div>

        {/* Command List */}
        <div
          ref={listRef}
          className="max-h-72 overflow-y-auto p-1"
          role="listbox"
        >
          {filtered.length === 0 ? (
            <p className="py-6 text-center text-sm text-muted-foreground">
              No results found.
            </p>
          ) : (
            Array.from(grouped.entries()).map(([category, cmds]) => (
              <div key={category} role="group" aria-label={category || 'Commands'}>
                {category && (
                  <p className="px-2 py-1.5 text-xs font-medium text-muted-foreground">
                    {category}
                  </p>
                )}
                {cmds.map((cmd) => {
                  const idx = flatIndex++;
                  const isActive = idx === activeIndex;
                  return (
                    <button
                      key={cmd.id}
                      role="option"
                      aria-selected={isActive}
                      data-active={isActive}
                      className={cn(
                        'flex w-full items-center gap-2 rounded-md px-2 py-2 text-sm transition-colors',
                        isActive
                          ? 'bg-accent text-accent-foreground'
                          : 'text-foreground hover:bg-accent/50',
                      )}
                      onClick={() => {
                        onSelect(cmd);
                        onClose();
                      }}
                      onMouseEnter={() => setActiveIndex(idx)}
                    >
                      {cmd.icon && <span className="shrink-0">{cmd.icon}</span>}
                      <span className="flex-1 text-left">{cmd.label}</span>
                      {cmd.shortcut && (
                        <kbd className="ml-auto rounded border bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground">
                          {cmd.shortcut}
                        </kbd>
                      )}
                    </button>
                  );
                })}
              </div>
            ))
          )}
        </div>
      </div>
    </div>
  );
}
