import type { CommandDef, CommandManifest } from '@mosaicstack/types';

// Local-only commands (work even when gateway is disconnected)
const LOCAL_COMMANDS: CommandDef[] = [
  {
    name: 'help',
    description: 'Show available commands',
    aliases: ['h'],
    args: undefined,
    execution: 'local',
    available: true,
    scope: 'core',
  },
  {
    name: 'stop',
    description: 'Cancel current streaming response',
    aliases: [],
    args: undefined,
    execution: 'local',
    available: true,
    scope: 'core',
  },
  {
    name: 'cost',
    description: 'Show token usage and cost for current session',
    aliases: [],
    args: undefined,
    execution: 'local',
    available: true,
    scope: 'core',
  },
  {
    name: 'status',
    description: 'Show connection and session status',
    aliases: ['s'],
    args: undefined,
    execution: 'local',
    available: true,
    scope: 'core',
  },
  {
    name: 'history',
    description: 'Show conversation message count and context usage',
    aliases: ['hist'],
    args: undefined,
    execution: 'local',
    available: true,
    scope: 'core',
  },
  {
    name: 'clear',
    description: 'Clear the current conversation display',
    aliases: [],
    args: undefined,
    execution: 'local',
    available: true,
    scope: 'core',
  },
  {
    name: 'attach',
    description: 'Attach a file to the next message (@file syntax also works inline)',
    aliases: [],
    args: [
      {
        name: 'path',
        type: 'string' as const,
        optional: false,
        description: 'File path to attach',
      },
    ],
    execution: 'local',
    available: true,
    scope: 'core',
  },
  {
    name: 'new',
    description: 'Start a new conversation',
    aliases: ['n'],
    args: undefined,
    execution: 'local',
    available: true,
    scope: 'core',
  },
];

const ALIASES: Record<string, string> = {
  m: 'model',
  t: 'thinking',
  a: 'agent',
  s: 'status',
  h: 'help',
  hist: 'history',
  pref: 'preferences',
};

export class CommandRegistry {
  private gatewayManifest: CommandManifest | null = null;

  updateManifest(manifest: CommandManifest): void {
    this.gatewayManifest = manifest;
  }

  resolveAlias(command: string): string {
    return ALIASES[command] ?? command;
  }

  find(command: string): CommandDef | null {
    const resolved = this.resolveAlias(command);
    // Search local first, then gateway manifest
    const local = LOCAL_COMMANDS.find((c) => c.name === resolved || c.aliases.includes(resolved));
    if (local) return local;
    if (this.gatewayManifest) {
      return (
        this.gatewayManifest.commands.find(
          (c) => c.name === resolved || c.aliases.includes(resolved),
        ) ?? null
      );
    }
    return null;
  }

  getAll(): CommandDef[] {
    const gateway = this.gatewayManifest?.commands ?? [];
    // Local commands take precedence; deduplicate gateway commands that share
    // a name with a local command to avoid duplicate React keys and confusing
    // autocomplete entries.
    const localNames = new Set(LOCAL_COMMANDS.map((c) => c.name));
    const dedupedGateway = gateway.filter((c) => !localNames.has(c.name));
    return [...LOCAL_COMMANDS, ...dedupedGateway];
  }

  getLocalCommands(): CommandDef[] {
    return LOCAL_COMMANDS;
  }
}

export const commandRegistry = new CommandRegistry();
