import type { CommandDefinition, CommandResult } from '../types.js';
import type { CommandRegistry } from '../registry.js';

function notAvailable(label: string): CommandResult {
  return {
    handled: true,
    text: `${label} is not available in this session.`,
  };
}

export function createHelpCommand(registry: CommandRegistry): CommandDefinition {
  return {
    name: 'help',
    description: 'Show available commands',
    execute: async () => {
      const lines = ['Available commands:'];
      for (const command of registry.list()) {
        const aliases = command.aliases && command.aliases.length > 0
          ? ` (aliases: ${command.aliases.map(alias => `/${alias}`).join(', ')})`
          : '';
        lines.push(`- /${command.name}: ${command.description}${aliases}`);
      }
      return {
        handled: true,
        text: lines.join('\n'),
      };
    },
  };
}

export function createStatusCommand(): CommandDefinition {
  return {
    name: 'status',
    description: 'Show current status',
    execute: async (_args, ctx) => {
      if (!ctx.services?.getStatus) {
        return {
          handled: true,
          text: 'Flynn is running.',
        };
      }

      return {
        handled: true,
        text: await ctx.services.getStatus(),
      };
    },
  };
}

export function createToolsCommand(): CommandDefinition {
  return {
    name: 'tools',
    description: 'Show available tools in this session',
    execute: async (_args, ctx) => {
      if (!ctx.services?.getTools) {
        return notAvailable('Tools command');
      }
      return {
        handled: true,
        text: await ctx.services.getTools(),
      };
    },
  };
}

export function createUsageCommand(): CommandDefinition {
  return {
    name: 'usage',
    description: 'Show token usage',
    execute: async (_args, ctx) => {
      if (!ctx.services?.getUsage) {
        return notAvailable('Usage command');
      }

      return {
        handled: true,
        text: await ctx.services.getUsage(),
      };
    },
  };
}

export function createContextCommand(): CommandDefinition {
  return {
    name: 'context',
    description: 'Show context window usage',
    execute: async (_args, ctx) => {
      if (!ctx.services?.getContext) {
        return notAvailable('Context command');
      }
      return {
        handled: true,
        text: await ctx.services.getContext(),
      };
    },
  };
}

export function createModelCommand(): CommandDefinition {
  return {
    name: 'model',
    description: 'Show or change model tier',
    execute: async (args, ctx) => {
      if (args.length === 0) {
        if (!ctx.services?.getModel) {
          return notAvailable('Model command');
        }
        return {
          handled: true,
          text: await ctx.services.getModel(),
        };
      }

      if (!ctx.services?.setModel) {
        return notAvailable('Model command');
      }

      return {
        handled: true,
        // Pass through the full argument string so frontends can support
        // richer syntax like: /model <tier> <provider/model>
        text: await ctx.services.setModel(args.join(' ')),
      };
    },
  };
}

export function createCompactCommand(): CommandDefinition {
  return {
    name: 'compact',
    description: 'Compact conversation context',
    execute: async (_args, ctx) => {
      if (!ctx.services?.compact) {
        return notAvailable('Compact command');
      }

      return {
        handled: true,
        text: await ctx.services.compact(),
      };
    },
  };
}

export function createResetCommand(): CommandDefinition {
  return {
    name: 'reset',
    description: 'Reset current session',
    execute: async (_args, ctx) => {
      if (!ctx.services?.reset) {
        return notAvailable('Reset command');
      }

      return {
        handled: true,
        text: await ctx.services.reset(),
      };
    },
  };
}

export function createStopCommand(): CommandDefinition {
  return {
    name: 'stop',
    aliases: ['cancel'],
    description: 'Stop the current in-flight run',
    execute: async (_args, ctx) => {
      if (!ctx.services?.cancelRun) {
        return notAvailable('Stop command');
      }
      return {
        handled: true,
        text: await ctx.services.cancelRun(),
      };
    },
  };
}

export function createElevateCommand(): CommandDefinition {
  return {
    name: 'elevate',
    description: 'Enable or disable time-bounded elevated host mode',
    execute: async (args, ctx) => {
      if (args.length === 0) {
        if (!ctx.services?.getElevation) {
          return notAvailable('Elevate command');
        }
        return { handled: true, text: await ctx.services.getElevation() };
      }

      if (!ctx.services?.setElevation) {
        return notAvailable('Elevate command');
      }

      return { handled: true, text: await ctx.services.setElevation(args.join(' ')) };
    },
  };
}

export function createQueueCommand(): CommandDefinition {
  return {
    name: 'queue',
    description: 'Inspect or update per-session queue policy',
    execute: async (args, ctx) => {
      if (args.length === 0 || args[0] === 'show') {
        if (!ctx.services?.getQueue) {
          return notAvailable('Queue command');
        }
        return { handled: true, text: await ctx.services.getQueue() };
      }

      const [action, ...rest] = args;
      if (action === 'reset') {
        if (!ctx.services?.resetQueue) {
          return notAvailable('Queue command');
        }
        return { handled: true, text: await ctx.services.resetQueue() };
      }

      if (!ctx.services?.setQueue) {
        return notAvailable('Queue command');
      }

      const input = action === 'set' ? rest.join(' ') : args.join(' ');
      return { handled: true, text: await ctx.services.setQueue(input) };
    },
  };
}

export function createResearchCommand(): CommandDefinition {
  return {
    name: 'research',
    description: 'Delegate a task to the configured research sub-agent',
    execute: async (args, ctx) => {
      const task = args.join(' ').trim();
      if (!task) {
        return {
          handled: true,
          text: 'Usage: /research <question or task>',
        };
      }
      if (!ctx.services?.delegateAgent) {
        return notAvailable('Research command');
      }
      return {
        handled: true,
        text: await ctx.services.delegateAgent('research', task),
      };
    },
  };
}

export function createCouncilCommand(): CommandDefinition {
  return {
    name: 'council',
    description: 'Run the D/P councils pipeline for a task',
    execute: async (args, ctx) => {
      const task = args.join(' ').trim();
      if (!task) {
        return {
          handled: true,
          text: 'Usage: /council <question or task> | /council preflight',
        };
      }
      if (!ctx.services?.runCouncil) {
        return notAvailable('Council command');
      }
      return {
        handled: true,
        text: await ctx.services.runCouncil(task),
      };
    },
  };
}

export function createTransferCommand(): CommandDefinition {
  return {
    name: 'transfer',
    description: 'Transfer session to another frontend',
    execute: async (args, ctx) => {
      if (!ctx.services?.transferSession) {
        return notAvailable('Transfer command');
      }

      const target = args.join(' ').trim();
      return {
        handled: true,
        text: await ctx.services.transferSession(target),
      };
    },
  };
}

export function createApprovalsCommand(): CommandDefinition {
  return {
    name: 'approvals',
    description: 'Show pending approval gates for this session',
    execute: async (_args, ctx) => {
      if (!ctx.services?.getApprovals) {
        return notAvailable('Approvals command');
      }
      return {
        handled: true,
        text: await ctx.services.getApprovals(),
      };
    },
  };
}

export function createApproveCommand(): CommandDefinition {
  return {
    name: 'approve',
    description: 'Approve a pending gate (latest by default, or by id)',
    execute: async (args, ctx) => {
      if (!ctx.services?.approvePending) {
        return notAvailable('Approve command');
      }
      return {
        handled: true,
        text: await ctx.services.approvePending(args.join(' ').trim()),
      };
    },
  };
}

export function createDenyCommand(): CommandDefinition {
  return {
    name: 'deny',
    description: 'Deny a pending gate (latest by default, optional id and reason)',
    execute: async (args, ctx) => {
      if (!ctx.services?.denyPending) {
        return notAvailable('Deny command');
      }
      return {
        handled: true,
        text: await ctx.services.denyPending(args.join(' ').trim()),
      };
    },
  };
}

export function createSkillCommand(): CommandDefinition {
  return {
    name: 'skill',
    description: 'In-chat skill discovery and install (list/search/install)',
    execute: async (args, ctx) => {
      if (!ctx.services?.skillCommand) {
        return notAvailable('Skill command');
      }
      return {
        handled: true,
        text: await ctx.services.skillCommand(args.join(' ').trim()),
      };
    },
  };
}

export function createBackendCommand(): CommandDefinition {
  return {
    name: 'backend',
    aliases: ['runtime'],
    description: 'Inspect or control runtime backend mode (status, activate pi, deactivate pi, use config)',
    execute: async (args, ctx) => {
      if (!ctx.services?.backendCommand) {
        return notAvailable('Backend command');
      }
      return {
        handled: true,
        text: await ctx.services.backendCommand(args.join(' ').trim()),
      };
    },
  };
}

export function registerBuiltinCommands(registry: CommandRegistry): void {
  registry.register(createHelpCommand(registry));
  registry.register(createStatusCommand());
  registry.register(createToolsCommand());
  registry.register(createUsageCommand());
  registry.register(createContextCommand());
  registry.register(createResearchCommand());
  registry.register(createCouncilCommand());
  registry.register(createModelCommand());
  registry.register(createCompactCommand());
  registry.register(createResetCommand());
  registry.register(createStopCommand());
  registry.register(createElevateCommand());
  registry.register(createQueueCommand());
  registry.register(createTransferCommand());
  registry.register(createApprovalsCommand());
  registry.register(createApproveCommand());
  registry.register(createDenyCommand());
  registry.register(createSkillCommand());
  registry.register(createBackendCommand());
}
