'use client';

/**
 * Global command palette (Cmd+K / Ctrl+K).
 * Dynamic: fetches real projects, repos, rooms from API.
 * Actions: navigate to project/repo/room, create project, create repo.
 */

import { useState, useEffect, useCallback, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import {
  CommandDialog,
  CommandInput,
  CommandList,
  CommandEmpty,
  CommandGroup,
  CommandItem,
  CommandShortcut,
} from '@/components/ui/command';
import {
  FolderKanban,
  GitBranch,
  Hash,
  Plus,
  Bell,
  Search,
} from 'lucide-react';
import { getRegisteredCommands } from '@/hooks/useCommandRegistry';
import type { CommandItem as RegistryCommandItem } from '@/hooks/useCommandRegistry';
import { formatShortcut } from '@/hooks/useKeyboardShortcut';
import { getCurrentUserProjects, projectRepos, roomList } from '@/client';
import type { UserProjectInfo, ProjectRepositoryItem, RoomResponse } from '@/client';

// ── Icons ────────────────────────────────────────────────────────────────────

const iconMap: Record<string, React.ComponentType<{ className?: string }>> = {
  FolderKanban,
  GitBranch,
  Hash,
  Plus,
  Bell,
  Search,
};

// ── Command item type ────────────────────────────────────────────────────────

interface PaletteItem {
  id: string;
  label: string;
  icon: string;
  shortcut?: { key: string; meta?: boolean; shift?: boolean };
  action: () => void;
  group: string;
  keywords: string[];
}

// ── Static quick actions ─────────────────────────────────────────────────────

function buildStaticActions(navigate: ReturnType<typeof useNavigate>): PaletteItem[] {
  return [
    {
      id: 'goto-notifications',
      label: 'Go to Notifications',
      icon: 'Bell',
      shortcut: { key: 'n', meta: true },
      action: () => navigate('/notify'),
      group: 'Navigation',
      keywords: ['goto', 'notifications', 'inbox'],
    },
    {
      id: 'create-project',
      label: 'Create Project',
      icon: 'Plus',
      shortcut: { key: 'c', meta: true, shift: true },
      action: () => navigate('/init/project'),
      group: 'Create',
      keywords: ['create', 'new', 'project'],
    },
  ];
}

// ── Main palette ─────────────────────────────────────────────────────────────

export function CommandPalette() {
  const [open, setOpen] = useState(false);
  const navigate = useNavigate();

  // Fetch projects for the current user (no workspace dependency)
  const { data: projectsData } = useQuery({
    queryKey: ['commandPaletteProjects'],
    queryFn: async () => {
      const resp = await getCurrentUserProjects();
      return resp.data?.data ?? { projects: [] as UserProjectInfo[], total_count: 0 };
    },
  });

  const projects = projectsData?.projects ?? [];

  // Derived project names for repo/room queries
  const projectNames = useMemo(
    () => projects.map(p => p.name),
    [projects],
  );

  // Fetch repos per project (up to 5 projects to keep it fast)
  const { data: reposData } = useQuery({
    queryKey: ['commandPaletteRepos', projectNames],
    queryFn: async () => {
      const results: Record<string, ProjectRepositoryItem[]> = {};
      for (const name of projectNames.slice(0, 5)) {
        try {
          const resp = await projectRepos({ path: { project_name: name } });
          const data = resp.data?.data;
          if (data?.items) results[name] = data.items;
        } catch { /* skip */ }
      }
      return results;
    },
    enabled: projectNames.length > 0,
  });

  // Fetch rooms for each project (up to 5 to keep it fast)

  const { data: roomsData } = useQuery({
    queryKey: ['commandPaletteRooms', projectNames],
    queryFn: async () => {
      const results: Record<string, RoomResponse[]> = {};
      for (const name of projectNames.slice(0, 5)) {
        try {
          const resp = await roomList({ path: { project_name: name } });
          const data = resp.data?.data;
          if (data) results[name] = (data as any)?.rooms ?? (Array.isArray(data) ? data : []);
        } catch { /* skip */ }
      }
      return results;
    },
    enabled: projectNames.length > 0,
  });

  // Global shortcut: Ctrl+Alt+F (Windows/Linux) or Cmd+Ctrl+F (Mac)
  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      const isMac = navigator.platform?.toUpperCase().includes('MAC') || navigator.userAgent?.includes('Mac');
      const match = isMac
        ? e.metaKey && e.ctrlKey && e.key === 'f'
        : e.ctrlKey && e.altKey && e.key === 'f';
      if (match) {
        e.preventDefault();
        setOpen((v) => !v);
      }
    };
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  }, []);

  // Close on navigation
  useEffect(() => {
    const handler = () => setOpen(false);
    window.addEventListener('popstate', handler);
    return () => window.removeEventListener('popstate', handler);
  }, []);

  const handleSelect = useCallback((action: () => void) => {
    setOpen(false);
    action();
  }, []);

  // Build search text including keywords for cmdk filtering
  const searchValue = useCallback((item: PaletteItem | RegistryCommandItem) => {
    return [item.label, ...(item.keywords ?? [])].join(' ');
  }, []);

  // ── Build dynamic command list ──────────────────────────────────────────

  const allRooms = roomsData ?? {};
  const allRepos = reposData ?? {};

  const projectItems: PaletteItem[] = projects.map(p => ({
    id: `project-${p.name}`,
    label: p.display_name || p.name,
    icon: 'FolderKanban',
    action: () => navigate(`/project/${p.name}`),
    group: 'Projects',
    keywords: ['project', p.name, p.display_name, ...(p.description ? [p.description] : [])],
  }));

  const repoItems: PaletteItem[] = [];
  for (const [projName, repos] of Object.entries(allRepos)) {
    for (const r of repos) {
      repoItems.push({
        id: `repo-${projName}-${r.repo_name}`,
        label: `${r.repo_name} (${projName})`,
        icon: 'GitBranch',
        action: () => navigate(`/repository/${projName}/${r.repo_name}`),
        group: 'Repositories',
        keywords: ['repo', 'repository', r.repo_name, projName, ...(r.description ? [r.description] : [])],
      });
    }
  }

  const roomItems: PaletteItem[] = [];
  for (const [projName, rooms] of Object.entries(allRooms)) {
    for (const r of rooms) {
      roomItems.push({
        id: `room-${r.id}`,
        label: `${r.room_name} (${projName})`,
        icon: 'Hash',
        action: () => navigate(`/project/${projName}/room/${r.id}`),
        group: 'Rooms',
        keywords: ['room', 'chat', 'channel', r.room_name, projName],
      });
    }
  }

  // Per-project "create repo" actions
  const createRepoItems: PaletteItem[] = projects.slice(0, 10).map(p => ({
    id: `create-repo-${p.name}`,
    label: `Create Repo in ${p.display_name || p.name}`,
    icon: 'Plus',
    action: () => navigate(`/project/${p.name}/repositories`),
    group: 'Create',
    keywords: ['create', 'new', 'repo', 'repository', p.name, p.display_name],
  }));

  const staticActions = buildStaticActions(navigate);
  const registered = getRegisteredCommands();
  const allCommands = [
    ...staticActions,
    ...projectItems,
    ...repoItems,
    ...roomItems,
    ...createRepoItems,
    ...registered,
  ] as (PaletteItem | RegistryCommandItem)[];

  // Group commands by their `group` field
  const grouped = useMemo(() => {
    const groups = new Map<string, (PaletteItem | RegistryCommandItem)[]>();
    for (const cmd of allCommands) {
      const g = groups.get(cmd.group) ?? [];
      g.push(cmd);
      groups.set(cmd.group, g);
    }
    return groups;
  }, [allCommands]);

  return (
    <CommandDialog open={open} onOpenChange={setOpen}>
      <CommandInput placeholder="Search projects, repos, rooms, commands…" autoFocus />
      <CommandList>
        <CommandEmpty>No results found.</CommandEmpty>
        {Array.from(grouped.entries()).map(([group, cmds]) => (
          <CommandGroup key={group} heading={group}>
            {cmds.map((cmd) => {
              const Icon = iconMap[(cmd as PaletteItem).icon ?? ''] ?? Search;
              const shortcut = cmd.shortcut;
              return (
                <CommandItem
                  key={cmd.id}
                  value={searchValue(cmd)}
                  onSelect={() => handleSelect(cmd.action)}
                >
                  <Icon className="mr-2 h-4 w-4 shrink-0" />
                  <span className="flex-1">{cmd.label}</span>
                  {shortcut && (
                    <CommandShortcut>{formatShortcut(shortcut)}</CommandShortcut>
                  )}
                </CommandItem>
              );
            })}
          </CommandGroup>
        ))}
      </CommandList>
    </CommandDialog>
  );
}