/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import type {
  SlashCommand,
  CommandContext,
  SlashCommandActionReturn,
} from './types.js';
import { CommandKind } from './types.js';
import { MessageType, type HistoryItemAgentsList } from '../types.js';
import { SettingScope } from '../../config/settings.js';
import { disableAgent, enableAgent } from '../../utils/agentSettings.js';
import { renderAgentActionFeedback } from '../../utils/agentUtils.js';

const agentsListCommand: SlashCommand = {
  name: 'list',
  description: 'List available local and remote agents',
  kind: CommandKind.BUILT_IN,
  autoExecute: true,
  action: async (context: CommandContext) => {
    const config = context.services.agentContext?.config;
    if (!config) {
      return {
        type: 'message',
        messageType: 'error',
        content: 'Config not loaded.',
      };
    }

    const agentRegistry = config.getAgentRegistry();
    if (!agentRegistry) {
      return {
        type: 'message',
        messageType: 'error',
        content: 'Agent registry not found.',
      };
    }

    const agents = agentRegistry.getAllDefinitions().map((def) => ({
      name: def.name,
      displayName: def.displayName,
      description: def.description,
      kind: def.kind,
    }));

    const agentsListItem: HistoryItemAgentsList = {
      type: MessageType.AGENTS_LIST,
      agents,
    };

    context.ui.addItem(agentsListItem);

    return;
  },
};

async function enableAction(
  context: CommandContext,
  args: string,
): Promise<SlashCommandActionReturn | void> {
  const config = context.services.agentContext?.config;
  const { settings } = context.services;
  if (!config) {
    return {
      type: 'message',
      messageType: 'error',
      content: 'Config not loaded.',
    };
  }

  const agentName = args.trim();
  if (!agentName) {
    return {
      type: 'message',
      messageType: 'error',
      content: 'Usage: /agents enable <agent-name>',
    };
  }

  const agentRegistry = config.getAgentRegistry();
  if (!agentRegistry) {
    return {
      type: 'message',
      messageType: 'error',
      content: 'Agent registry not found.',
    };
  }

  const allAgents = agentRegistry.getAllAgentNames();
  const overrides = settings.merged.agents.overrides;
  const disabledAgents = Object.keys(overrides).filter(
    (name) => overrides[name]?.enabled === false,
  );

  if (allAgents.includes(agentName) && !disabledAgents.includes(agentName)) {
    return {
      type: 'message',
      messageType: 'info',
      content: `Agent '${agentName}' is already enabled.`,
    };
  }

  if (!disabledAgents.includes(agentName) && !allAgents.includes(agentName)) {
    return {
      type: 'message',
      messageType: 'error',
      content: `Agent '${agentName}' not found.`,
    };
  }

  const result = enableAgent(settings, agentName);

  if (result.status === 'no-op') {
    return {
      type: 'message',
      messageType: 'info',
      content: renderAgentActionFeedback(result, (l, p) => `${l} (${p})`),
    };
  }

  context.ui.addItem({
    type: MessageType.INFO,
    text: `Enabling ${agentName}...`,
  });
  await agentRegistry.reload();

  return {
    type: 'message',
    messageType: 'info',
    content: renderAgentActionFeedback(result, (l, p) => `${l} (${p})`),
  };
}

async function disableAction(
  context: CommandContext,
  args: string,
): Promise<SlashCommandActionReturn | void> {
  const config = context.services.agentContext?.config;
  const { settings } = context.services;
  if (!config) {
    return {
      type: 'message',
      messageType: 'error',
      content: 'Config not loaded.',
    };
  }

  const agentName = args.trim();
  if (!agentName) {
    return {
      type: 'message',
      messageType: 'error',
      content: 'Usage: /agents disable <agent-name>',
    };
  }

  const agentRegistry = config.getAgentRegistry();
  if (!agentRegistry) {
    return {
      type: 'message',
      messageType: 'error',
      content: 'Agent registry not found.',
    };
  }

  const allAgents = agentRegistry.getAllAgentNames();
  const overrides = settings.merged.agents.overrides;
  const disabledAgents = Object.keys(overrides).filter(
    (name) => overrides[name]?.enabled === false,
  );

  if (disabledAgents.includes(agentName)) {
    return {
      type: 'message',
      messageType: 'info',
      content: `Agent '${agentName}' is already disabled.`,
    };
  }

  if (!allAgents.includes(agentName)) {
    return {
      type: 'message',
      messageType: 'error',
      content: `Agent '${agentName}' not found.`,
    };
  }

  const scope = context.services.settings.workspace.path
    ? SettingScope.Workspace
    : SettingScope.User;
  const result = disableAgent(settings, agentName, scope);

  if (result.status === 'no-op') {
    return {
      type: 'message',
      messageType: 'info',
      content: renderAgentActionFeedback(result, (l, p) => `${l} (${p})`),
    };
  }

  context.ui.addItem({
    type: MessageType.INFO,
    text: `Disabling ${agentName}...`,
  });
  await agentRegistry.reload();

  return {
    type: 'message',
    messageType: 'info',
    content: renderAgentActionFeedback(result, (l, p) => `${l} (${p})`),
  };
}

async function configAction(
  context: CommandContext,
  args: string,
): Promise<SlashCommandActionReturn | void> {
  const config = context.services.agentContext?.config;
  if (!config) {
    return {
      type: 'message',
      messageType: 'error',
      content: 'Config not loaded.',
    };
  }

  const agentName = args.trim();
  if (!agentName) {
    return {
      type: 'message',
      messageType: 'error',
      content: 'Usage: /agents config <agent-name>',
    };
  }

  const agentRegistry = config.getAgentRegistry();
  if (!agentRegistry) {
    return {
      type: 'message',
      messageType: 'error',
      content: 'Agent registry not found.',
    };
  }

  const definition = agentRegistry.getDiscoveredDefinition(agentName);
  if (!definition) {
    return {
      type: 'message',
      messageType: 'error',
      content: `Agent '${agentName}' not found.`,
    };
  }

  const displayName = definition.displayName || agentName;

  return {
    type: 'dialog',
    dialog: 'agentConfig',
    props: {
      name: agentName,
      displayName,
      definition,
    },
  };
}

function completeAgentsToEnable(context: CommandContext, partialArg: string) {
  const config = context.services.agentContext?.config;
  const { settings } = context.services;
  if (!config) return [];

  const overrides = settings.merged.agents.overrides;
  const disabledAgents = Object.entries(overrides)
    .filter(([_, override]) => override?.enabled === false)
    .map(([name]) => name);

  return disabledAgents.filter((name) => name.startsWith(partialArg));
}

function completeAgentsToDisable(context: CommandContext, partialArg: string) {
  const config = context.services.agentContext?.config;
  if (!config) return [];

  const agentRegistry = config.getAgentRegistry();
  const allAgents = agentRegistry ? agentRegistry.getAllAgentNames() : [];
  return allAgents.filter((name: string) => name.startsWith(partialArg));
}

function completeAllAgents(context: CommandContext, partialArg: string) {
  const config = context.services.agentContext?.config;
  if (!config) return [];

  const agentRegistry = config.getAgentRegistry();
  const allAgents = agentRegistry?.getAllDiscoveredAgentNames() ?? [];
  return allAgents.filter((name: string) => name.startsWith(partialArg));
}

const enableCommand: SlashCommand = {
  name: 'enable',
  description: 'Enable a disabled agent',
  kind: CommandKind.BUILT_IN,
  autoExecute: false,
  action: enableAction,
  completion: completeAgentsToEnable,
};

const disableCommand: SlashCommand = {
  name: 'disable',
  description: 'Disable an enabled agent',
  kind: CommandKind.BUILT_IN,
  autoExecute: false,
  action: disableAction,
  completion: completeAgentsToDisable,
};

const configCommand: SlashCommand = {
  name: 'config',
  description: 'Configure an agent',
  kind: CommandKind.BUILT_IN,
  autoExecute: false,
  action: configAction,
  completion: completeAllAgents,
};

const agentsReloadCommand: SlashCommand = {
  name: 'reload',
  altNames: ['refresh'],
  description: 'Reload the agent registry',
  kind: CommandKind.BUILT_IN,
  action: async (context: CommandContext) => {
    const config = context.services.agentContext?.config;
    const agentRegistry = config?.getAgentRegistry();
    if (!agentRegistry) {
      return {
        type: 'message',
        messageType: 'error',
        content: 'Agent registry not found.',
      };
    }

    context.ui.addItem({
      type: MessageType.INFO,
      text: 'Reloading agent registry...',
    });

    const summary = await agentRegistry.reload();

    let content =
      summary.errors.length > 0
        ? 'Agents reloaded with errors:'
        : 'Agents reloaded successfully:';
    content += `\n- Total: ${summary.totalLoaded} (${summary.localCount} local, ${summary.remoteCount} remote)`;

    if (summary.newAgents.length > 0) {
      content += `\n- New: ${summary.newAgents.join(', ')}`;
    }
    if (summary.updatedAgents.length > 0) {
      content += `\n- Updated: ${summary.updatedAgents.join(', ')}`;
    }
    if (summary.deletedAgents.length > 0) {
      content += `\n- Deleted: ${summary.deletedAgents.join(', ')}`;
    }
    if (summary.errors.length > 0) {
      content += `\n- Errors: ${summary.errors.length} encountered during reload`;
    }

    content += '\n\nRun /agents list to see all available agents.';

    return {
      type: 'message',
      messageType: 'info',
      content,
    };
  },
};

export const agentsCommand: SlashCommand = {
  name: 'agents',
  description: 'Manage agents',
  kind: CommandKind.BUILT_IN,
  subCommands: [
    agentsListCommand,
    agentsReloadCommand,
    enableCommand,
    disableCommand,
    configCommand,
  ],
  action: async (context: CommandContext, args) =>
    // Default to list if no subcommand is provided
    agentsListCommand.action!(context, args),
};
