import { useEffect, useMemo, useRef, useState } from 'react';
import { cn } from '@/lib/utils';
import type { Skill } from '@/api/types';

interface Props {
  query: string;
  skills: Skill[];
  anchorRect: { top: number; left: number };
  onSelect: (skillName: string) => void;
  onClose: () => void;
}

// Batch 9.6: slash-command dropdown. Models FileMentionPopover's pattern —
// fixed-positioned popover, keyboard nav, click-outside-to-close. shadcn
// `Command` (cmdk) isn't installed in this project; per the addendum we use
// a plain div + Tailwind instead of pulling a new primitive autonomously.

// Case-insensitive prefix match on `name` only. Description is display-only
// in v1 (substring search across description is deferred to a polish batch).
function filterByPrefix(skills: Skill[], query: string): Skill[] {
  const q = query.toLowerCase();
  const filtered = q
    ? skills.filter((s) => s.name.toLowerCase().startsWith(q))
    : skills;
  // Stable alphabetical ordering matches the server's cache order (skills.ts
  // sorts on name asc) but we re-sort here so a stale client cache doesn't
  // surprise the user.
  return [...filtered].sort((a, b) => a.name.localeCompare(b.name));
}

export function SkillSlashCommand({ query, skills, anchorRect, onSelect, onClose }: Props) {
  const [highlightIndex, setHighlightIndex] = useState(0);
  const popoverRef = useRef<HTMLDivElement>(null);
  const filtered = useMemo(() => filterByPrefix(skills, query), [skills, query]);

  useEffect(() => { setHighlightIndex(0); }, [query]);

  // Arrow / Enter / Tab / Escape. Bound on document so keystrokes from the
  // textarea reach the popover even though focus stays in the textarea.
  useEffect(() => {
    function handleKeyDown(e: KeyboardEvent) {
      if (e.key === 'ArrowDown') {
        e.preventDefault();
        setHighlightIndex((prev) => (prev < filtered.length - 1 ? prev + 1 : 0));
      } else if (e.key === 'ArrowUp') {
        e.preventDefault();
        setHighlightIndex((prev) => (prev > 0 ? prev - 1 : filtered.length - 1));
      } else if (e.key === 'Enter' || e.key === 'Tab') {
        if (filtered.length === 0) return;
        e.preventDefault();
        const target = filtered[highlightIndex] ?? filtered[0];
        if (target) onSelect(target.name);
      } else if (e.key === 'Escape') {
        e.preventDefault();
        onClose();
      }
    }
    document.addEventListener('keydown', handleKeyDown);
    return () => document.removeEventListener('keydown', handleKeyDown);
  }, [filtered, highlightIndex, onSelect, onClose]);

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

  useEffect(() => {
    const el = popoverRef.current?.querySelector('[data-highlighted="true"]');
    if (el) el.scrollIntoView({ block: 'nearest' });
  }, [highlightIndex]);

  // Anchor sits above the input — translate(-100%) on Y so the dropdown
  // expands upward from the anchor point rather than over the textarea.
  const style = {
    top: anchorRect.top,
    left: anchorRect.left,
    transform: 'translateY(-100%)',
  } as const;

  if (filtered.length === 0) {
    return (
      <div
        ref={popoverRef}
        className="fixed z-50 bg-popover border border-border rounded-md shadow min-w-[320px] p-2"
        style={style}
      >
        <div className="text-xs text-muted-foreground px-2 py-1">
          {query ? `No skill starts with "/${query}"` : 'No skills available'}
        </div>
      </div>
    );
  }

  return (
    <div
      ref={popoverRef}
      className="fixed z-50 bg-popover border border-border rounded-md shadow min-w-[320px] max-w-[420px] max-h-[320px] overflow-y-auto"
      style={style}
    >
      {filtered.map((skill, i) => (
        <button
          key={skill.name}
          type="button"
          data-highlighted={i === highlightIndex}
          className={cn(
            'w-full text-left px-2.5 py-2 cursor-pointer block',
            i === highlightIndex && 'bg-muted',
          )}
          onMouseEnter={() => setHighlightIndex(i)}
          onMouseDown={(e) => {
            // mousedown not click — click runs after blur/focus shuffles which
            // can race with the textarea's onBlur close path.
            e.preventDefault();
            onSelect(skill.name);
          }}
        >
          <div className="font-mono text-xs font-bold text-foreground">/{skill.name}</div>
          <div
            className="text-xs text-muted-foreground overflow-hidden"
            style={{
              display: '-webkit-box',
              WebkitLineClamp: 2,
              WebkitBoxOrient: 'vertical',
            }}
          >
            {skill.description}
          </div>
        </button>
      ))}
    </div>
  );
}
