import { useQuery } from '@tanstack/react-query';
import { useClient } from 'hooks/useClient';
import { useCapabilities } from 'hooks/useCapabilities';

export type TriggerConfig = { type: 'file'; extensions: string[] } | { type: 'directory' };

export type TaskSummary = {
  id: number;
  dirName: string;
  name: string;
  description: string;
  scope: string;
  category: string | null;
  triggers: TriggerConfig[];
  mode: 'script' | 'agentic' | 'pipeline';
  userId: number | null;
};

export type TaskGroup = { category: string; tasks: TaskSummary[] };

const UNCATEGORIZED = 'Other';

// Every task carries a `directory` trigger, so right-clicking a folder listed all of them at once.
// Grouping by category turns that into Run Task > Video > …
//
// The order comes from categories.yaml in the items store, not from here — adding a category is a
// change to that file plus the tasks using it, never to this code. Categories absent from the list
// sort alphabetically after the listed ones, and Other is always last.
const categoryRank = (category: string, order: string[]): number => {
  const known = order.indexOf(category);
  if (known !== -1) return known;
  return category === UNCATEGORIZED ? Number.MAX_SAFE_INTEGER : order.length;
};

// Shared with agents, which surface in the same context menu under their own submenu and obey the
// same categories.yaml ordering.
export const groupByCategory = <T extends { category: string | null; name: string }>(
  items: T[],
  order: string[] = [],
): Array<{ category: string; items: T[] }> => {
  const groups = new Map<string, T[]>();
  for (const item of items) {
    const category = item.category?.trim() || UNCATEGORIZED;
    const bucket = groups.get(category);
    if (bucket) bucket.push(item);
    else groups.set(category, [item]);
  }

  return Array.from(groups.entries())
    .map(([category, list]) => ({ category, items: [...list].sort((a, b) => a.name.localeCompare(b.name)) }))
    .sort(
      (a, b) =>
        categoryRank(a.category, order) - categoryRank(b.category, order) || a.category.localeCompare(b.category),
    );
};

export const groupTasksByCategory = (tasks: TaskSummary[], order: string[] = []): TaskGroup[] =>
  groupByCategory(tasks, order).map(({ category, items }) => ({ category, tasks: items }));

/** Does this item's trigger list cover the clicked entry? Identical rule for tasks and agents. */
export const matchesTrigger = (
  triggers: TriggerConfig[],
  fileName: string,
  entryType: 'file' | 'directory',
): boolean => {
  if (entryType === 'directory') return triggers.some((tr) => tr.type === 'directory');
  const ext = fileName.split('.').pop()?.toLowerCase();
  if (!ext) return false;
  return triggers.some((tr) => tr.type === 'file' && tr.extensions.includes(ext));
};

export const useTasks = () => {
  const client = useClient();
  // `tasks` is `kind: 'execution'`: a task run executes a script as the server owner. A member browsing
  // their own files has a file browser, not a task runner — so the context menu simply has no Run Task
  // submenu, and these two requests are not made. Without the guard they 403'd on every Files render.
  const { can } = useCapabilities();
  const allowed = can('tasks');

  const { data: tasks = [] } = useQuery<TaskSummary[]>({
    queryKey: ['tasks'],
    enabled: allowed,
    queryFn: () => client.get('/tasks'),
    staleTime: 60_000,
  });

  const { data: categoryOrder = [] } = useQuery<string[]>({
    queryKey: ['task-categories'],
    enabled: allowed,
    queryFn: () => client.get('/tasks/categories'),
    staleTime: 60_000,
  });

  const getMatchingTasks = (fileName: string, entryType: 'file' | 'directory'): TaskSummary[] =>
    tasks.filter((t) => matchesTrigger(t.triggers, fileName, entryType));

  // Grouped for the context menu, ordered by categories.yaml.
  const getMatchingTaskGroups = (fileName: string, entryType: 'file' | 'directory'): TaskGroup[] =>
    groupTasksByCategory(getMatchingTasks(fileName, entryType), categoryOrder);

  return { tasks, categoryOrder, getMatchingTasks, getMatchingTaskGroups };
};
