import type { SlashCommandData } from "../bridge/protocol.js";
import type { Command } from "../types/command.js";
import { getCommandName, isCommandEnabled } from "../types/command.js";

// <openspace-slash-commands:generated>
// Generated by python -m openspace.protocol.codegen --write
export type SlashCommandName =
  | "help"
  | "clear"
  | "status"
  | "compact"
  | "plan"
  | "summary"
  | "history"
  | "model"
  | "effort"
  | "tools"
  | "skills"
  | "save"
  | "load"
  | "exit"
  | "doctor"
  | "resume"
  | "cost"
  | "agent"
  | "background"
  | "agents"
  | "tasks"
  | "mcp"
  | "permissions"
  | "sandbox"
  | "copy"
  | "keybindings"
  | "vim"
  | "config"
  | "theme"
  | "review"
  | "diff"
  | "export"
  | "init"
  | "memory"
  | "dream";

export type SlashCommandCategory =
  | "session"
  | "navigation"
  | "tools"
  | "display"
  | "project";

export type SlashCommandArg = {
  name: string;
  required: boolean;
  description: string;
};

export type SlashCommandDefinition = Command & {
  name: SlashCommandName;
  summary: string;
  usage: string;
  category: SlashCommandCategory;
  args?: SlashCommandArg[];
  hidden?: boolean;
  implemented?: boolean;
};

export type ParsedSlashCommand = SlashCommandData & {
  args: string[];
  raw: string;
  definition: SlashCommandDefinition | null;
  isSupported: boolean;
};

const SLASH_COMMAND_REGISTRY: readonly SlashCommandDefinition[] = [
  {
    "handler": "local",
    "availability": [
      "local"
    ],
    "implemented": true,
    "name": "help",
    "description": "Show available commands.",
    "summary": "Show available commands.",
    "usage": "/help [command]",
    "category": "navigation",
    "aliases": [
      "h",
      "?"
    ],
    "args": [
      {
        "name": "command",
        "required": false,
        "description": "Command name for detailed help"
      }
    ]
  },
  {
    "handler": "local",
    "availability": [
      "local"
    ],
    "implemented": true,
    "name": "clear",
    "description": "Clear screen and message history.",
    "summary": "Clear screen and message history.",
    "usage": "/clear",
    "category": "navigation",
    "aliases": [
      "cls"
    ]
  },
  {
    "handler": "local",
    "availability": [
      "local"
    ],
    "implemented": true,
    "name": "status",
    "description": "Show session stats (tokens, cost, model, iterations).",
    "summary": "Show session stats (tokens, cost, model, iterations).",
    "usage": "/status",
    "category": "session"
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "compact",
    "description": "Manually trigger context compaction.",
    "summary": "Manually trigger context compaction.",
    "usage": "/compact [instructions]",
    "category": "session",
    "args": [
      {
        "name": "instructions",
        "required": false,
        "description": "Optional compaction instructions"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "plan",
    "description": "Enter plan mode for the next turn.",
    "summary": "Enter plan mode for the next turn.",
    "usage": "/plan",
    "category": "session"
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "summary",
    "description": "Update session memory for the active session.",
    "summary": "Update session memory for this session.",
    "usage": "/summary",
    "category": "session"
  },
  {
    "handler": "local",
    "availability": [
      "local"
    ],
    "implemented": true,
    "name": "history",
    "description": "Show prompt command history.",
    "summary": "Show prompt command history.",
    "usage": "/history [count]",
    "category": "session",
    "args": [
      {
        "name": "count",
        "required": false,
        "description": "Number of entries to show"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "model",
    "description": "View or switch the current model.",
    "summary": "View or switch the current model.",
    "usage": "/model [name]",
    "category": "tools",
    "aliases": [
      "m"
    ],
    "args": [
      {
        "name": "name",
        "required": false,
        "description": "Model name to switch to"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "effort",
    "description": "View or set reasoning effort.",
    "summary": "View or set reasoning effort.",
    "usage": "/effort [low|medium|high|max|auto]",
    "category": "tools",
    "args": [
      {
        "name": "level",
        "required": false,
        "description": "low, medium, high, max, or auto"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "tools",
    "description": "List available tools and their status.",
    "summary": "List available tools and their status.",
    "usage": "/tools [filter]",
    "category": "tools",
    "args": [
      {
        "name": "filter",
        "required": false,
        "description": "Filter tools by name"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "skills",
    "description": "List available skills and review runtime overlay suggestions.",
    "summary": "List skills or review runtime overlays.",
    "usage": "/skills [filter] | /skills overlay review [skill_id] | /skills overlay approve|reject <skill_id> [field ...]",
    "category": "tools",
    "args": [
      {
        "name": "filter",
        "required": false,
        "description": "Filter skills, or use overlay review/approve/reject"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "save",
    "description": "Persist the current session snapshot.",
    "summary": "Persist the current session snapshot.",
    "usage": "/save [name]",
    "category": "session",
    "args": [
      {
        "name": "name",
        "required": false,
        "description": "Optional session name"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "load",
    "description": "Load a saved session by ID.",
    "summary": "Load a saved session by ID.",
    "usage": "/load <session>",
    "category": "session",
    "args": [
      {
        "name": "session",
        "required": true,
        "description": "Session name or ID to load"
      }
    ]
  },
  {
    "handler": "local",
    "availability": [
      "local"
    ],
    "implemented": true,
    "name": "exit",
    "description": "Exit the TUI.",
    "summary": "Exit the TUI.",
    "usage": "/exit",
    "category": "navigation",
    "aliases": [
      "q",
      "quit"
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "doctor",
    "description": "Run diagnostic checks.",
    "summary": "Run diagnostic checks.",
    "usage": "/doctor",
    "category": "tools"
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "resume",
    "description": "List sessions or restore a previous session.",
    "summary": "List sessions or restore a previous session.",
    "usage": "/resume [session-id]",
    "category": "session",
    "args": [
      {
        "name": "session-id",
        "required": false,
        "description": "Session ID to restore"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "cost",
    "description": "Show the current accumulated cost.",
    "summary": "Show the current accumulated cost.",
    "usage": "/cost",
    "category": "session",
    "aliases": [
      "$$"
    ]
  },
  {
    "handler": "local",
    "availability": [
      "local"
    ],
    "implemented": true,
    "name": "agent",
    "description": "Send input to the viewed or specified background agent.",
    "summary": "Send input to a background agent.",
    "usage": "/agent [agent-id] <message>",
    "category": "tools",
    "args": [
      {
        "name": "agent-id",
        "required": false,
        "description": "Optional target agent id"
      },
      {
        "name": "message",
        "required": true,
        "description": "Input to send"
      }
    ]
  },
  {
    "handler": "local",
    "availability": [
      "local"
    ],
    "implemented": true,
    "name": "background",
    "description": "Control or refresh the background runtime.",
    "summary": "Control background runtime state.",
    "usage": "/background [start|stop|pause|resume|focus] [title|agent-id]",
    "category": "session",
    "aliases": [
      "bg"
    ],
    "args": [
      {
        "name": "action",
        "required": false,
        "description": "start, stop, pause, resume, or focus"
      },
      {
        "name": "value",
        "required": false,
        "description": "Optional title for start or agent id for focus"
      }
    ]
  },
  {
    "handler": "local",
    "availability": [
      "local"
    ],
    "implemented": true,
    "name": "agents",
    "description": "Toggle the agent runtime panel.",
    "summary": "Open or close the agent runtime panel.",
    "usage": "/agents",
    "category": "tools"
  },
  {
    "handler": "local",
    "availability": [
      "local"
    ],
    "implemented": true,
    "name": "tasks",
    "description": "Toggle the tasks panel.",
    "summary": "Open or close the tasks panel.",
    "usage": "/tasks",
    "category": "session"
  },
  {
    "handler": "local",
    "availability": [
      "local"
    ],
    "implemented": true,
    "name": "mcp",
    "description": "Toggle the MCP panel or reconnect a server.",
    "summary": "Inspect MCP status or reconnect a server.",
    "usage": "/mcp [reconnect <server>]",
    "category": "tools",
    "args": [
      {
        "name": "action",
        "required": false,
        "description": "Optional action such as reconnect"
      },
      {
        "name": "server",
        "required": false,
        "description": "Server name to reconnect"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "permissions",
    "description": "Show permission mode and rules.",
    "summary": "Inspect permission mode and rules.",
    "usage": "/permissions",
    "category": "display"
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "sandbox",
    "description": "Inspect or update process sandbox settings.",
    "summary": "Inspect or update sandbox settings.",
    "usage": "/sandbox [status|doctor|enable|disable|toggle|exclude]",
    "category": "display",
    "args": [
      {
        "name": "action",
        "required": false,
        "description": "status, doctor, enable, disable, toggle, exclude, or unexclude"
      },
      {
        "name": "value",
        "required": false,
        "description": "Optional mode, on/off value, or command pattern"
      }
    ]
  },
  {
    "handler": "local",
    "availability": [
      "local"
    ],
    "implemented": true,
    "name": "copy",
    "description": "Copy the latest message or full transcript to the clipboard.",
    "summary": "Copy transcript text to the clipboard.",
    "usage": "/copy [last|all]",
    "category": "display",
    "args": [
      {
        "name": "scope",
        "required": false,
        "description": "last or all"
      }
    ]
  },
  {
    "handler": "local",
    "availability": [
      "local"
    ],
    "implemented": true,
    "name": "keybindings",
    "description": "Show keybinding file location and load status.",
    "summary": "Inspect keybinding configuration.",
    "usage": "/keybindings",
    "category": "display"
  },
  {
    "handler": "local",
    "availability": [
      "local"
    ],
    "implemented": true,
    "name": "vim",
    "description": "Show or change the current Vim input mode.",
    "summary": "Inspect or toggle Vim mode.",
    "usage": "/vim [insert|normal|toggle]",
    "category": "display",
    "args": [
      {
        "name": "mode",
        "required": false,
        "description": "insert, normal, or toggle"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "config",
    "description": "View or modify local TUI settings.",
    "summary": "View or modify local TUI settings.",
    "usage": "/config [key] [value]",
    "category": "display",
    "aliases": [
      "settings"
    ],
    "args": [
      {
        "name": "key",
        "required": false,
        "description": "Setting key"
      },
      {
        "name": "value",
        "required": false,
        "description": "New value"
      }
    ]
  },
  {
    "handler": "local",
    "availability": [
      "local"
    ],
    "implemented": true,
    "name": "theme",
    "description": "Switch color theme.",
    "summary": "Switch color theme.",
    "usage": "/theme [name]",
    "category": "display",
    "args": [
      {
        "name": "name",
        "required": false,
        "description": "Theme name to apply"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "review",
    "description": "Start a code review on staged changes.",
    "summary": "Start a code review on staged changes.",
    "usage": "/review [path]",
    "category": "project",
    "aliases": [
      "cr"
    ],
    "args": [
      {
        "name": "path",
        "required": false,
        "description": "Limit review to a specific path"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "diff",
    "description": "Show diff of recent file changes.",
    "summary": "Show diff of recent file changes.",
    "usage": "/diff [path]",
    "category": "project",
    "args": [
      {
        "name": "path",
        "required": false,
        "description": "Path to diff"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "export",
    "description": "Export conversation to file.",
    "summary": "Export conversation to file.",
    "usage": "/export [format] [path]",
    "category": "session",
    "args": [
      {
        "name": "format",
        "required": false,
        "description": "Output format (md, json, txt)"
      },
      {
        "name": "path",
        "required": false,
        "description": "Output file path"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "init",
    "description": "Initialize project description file.",
    "summary": "Initialize project description file.",
    "usage": "/init",
    "category": "project"
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "memory",
    "description": "List or edit OpenSpace memory files.",
    "summary": "List or edit memory files.",
    "usage": "/memory [list|edit|read|logs]",
    "category": "project",
    "args": [
      {
        "name": "action",
        "required": false,
        "description": "list, edit, read, or logs"
      }
    ]
  },
  {
    "handler": "core",
    "availability": [
      "core"
    ],
    "implemented": true,
    "name": "dream",
    "description": "Manually consolidate auto-memory.",
    "summary": "Manually consolidate memory.",
    "usage": "/dream [--logs] [context]",
    "category": "project",
    "args": [
      {
        "name": "context",
        "required": false,
        "description": "Optional dream context or --logs"
      }
    ]
  }
] as const;

const CATEGORY_LABELS: Record<SlashCommandCategory, string> = {
  "session": "Session",
  "navigation": "Navigation",
  "tools": "Tools & Models",
  "display": "Display & Settings",
  "project": "Project"
};
// </openspace-slash-commands:generated>

const SLASH_COMMAND_BY_NAME = new Map<SlashCommandName, SlashCommandDefinition>(
  SLASH_COMMAND_REGISTRY.map(
    definition => [definition.name, definition] as const,
  ),
);

const ALIAS_TO_NAME = new Map<string, SlashCommandName>();
for (const def of SLASH_COMMAND_REGISTRY) {
  if (def.aliases) {
    for (const alias of def.aliases) {
      ALIAS_TO_NAME.set(alias, def.name);
    }
  }
}

export function resolveAlias(input: string): string {
  return ALIAS_TO_NAME.get(input) ?? input;
}

export function isSlashCommandName(
  command: string,
): command is SlashCommandName {
  return SLASH_COMMAND_BY_NAME.has(command as SlashCommandName);
}

export function getSlashCommandDefinition(
  command: string,
): SlashCommandDefinition | null {
  const resolved = resolveAlias(command);
  return isSlashCommandName(resolved)
    ? SLASH_COMMAND_BY_NAME.get(resolved) ?? null
    : null;
}

export function getSlashCommandSummaries(): readonly SlashCommandDefinition[] {
  return SLASH_COMMAND_REGISTRY.filter(
    command => !command.isHidden && isCommandEnabled(command),
  );
}

export function getCommandsByCategory(
  category: SlashCommandCategory,
): SlashCommandDefinition[] {
  return SLASH_COMMAND_REGISTRY.filter(
    command =>
      command.category === category &&
      !command.isHidden &&
      isCommandEnabled(command),
  );
}

export function getCommandCompletions(
  partial: string,
): SlashCommandDefinition[] {
  const lower = partial.toLowerCase();
  const seen = new Set<SlashCommandName>();
  const results: SlashCommandDefinition[] = [];

  for (const def of getSlashCommandSummaries()) {
    if (getCommandName(def).startsWith(lower)) {
      seen.add(def.name);
      results.push(def);
      continue;
    }

    if (def.aliases?.some(alias => alias.startsWith(lower))) {
      if (!seen.has(def.name)) {
        seen.add(def.name);
        results.push(def);
      }
    }
  }

  return results;
}

export function getLocalSlashCommands(): SlashCommandDefinition[] {
  return getSlashCommandSummaries().filter(command => command.handler === "local");
}

export function getCoreSlashCommands(): SlashCommandDefinition[] {
  return getSlashCommandSummaries().filter(command => command.handler === "core");
}

export function parseSlashCommandInput(raw: string): ParsedSlashCommand | null {
  const trimmed = raw.trim();
  if (!trimmed.startsWith("/")) {
    return null;
  }

  const parts = trimmed.slice(1).trim().split(/\s+/).filter(Boolean);
  const [rawCommand = "", ...args] = parts;
  const command = resolveAlias(rawCommand);
  const definition = getSlashCommandDefinition(command);

  return {
    raw: trimmed,
    command,
    args,
    definition,
    isSupported: definition !== null,
  };
}

export function formatSlashCommandHelpText(): string {
  const categories: SlashCommandCategory[] = [
    "session",
    "navigation",
    "tools",
    "display",
    "project",
  ];

  const lines: string[] = [];
  for (const category of categories) {
    const commands = getCommandsByCategory(category);
    if (commands.length === 0) {
      continue;
    }

    lines.push(`\n  ${CATEGORY_LABELS[category]}`);
    for (const command of commands) {
      const aliasStr =
        command.aliases && command.aliases.length > 0
          ? ` (${command.aliases.map(alias => `/${alias}`).join(", ")})`
          : "";
      const implementation =
        command.implemented === false ? " [planned]" : "";
      lines.push(
        `    /${command.name}${aliasStr}${implementation} — ${command.summary}`,
      );
    }
  }

  return `Available commands:${lines.join("\n")}`;
}

export function formatSlashCommandDetailText(
  command: SlashCommandDefinition,
): string {
  const lines = [
    command.usage,
    command.description || command.summary,
  ];
  if (command.aliases && command.aliases.length > 0) {
    lines.push(`Aliases: ${command.aliases.map(alias => `/${alias}`).join(", ")}`);
  }
  if (command.args && command.args.length > 0) {
    lines.push("Arguments:");
    for (const arg of command.args) {
      const marker = arg.required ? "required" : "optional";
      lines.push(`  ${arg.name} (${marker}) — ${arg.description}`);
    }
  }
  lines.push(`Handler: ${command.handler}`);
  return lines.join("\n");
}

export function formatSlashCommandStatus(parsed: ParsedSlashCommand): string {
  const commandText = parsed.command ? `/${parsed.command}` : "/";
  const argsText = parsed.args.length ? ` ${parsed.args.join(" ")}` : "";
  return `Sent ${commandText}${argsText}`;
}
