/** Integration tools — the CLI coding agents Forge wraps (claude code, codex,
 *  aider …): which are installed, which is the default, and per-component model
 *  overrides. "Is Claude integrated? Set it as default. Use different models for
 *  different components."
 *
 *  NOTE: these are CLI *agents* (settings.agents / defaultAgent), distinct from
 *  workspace agents/smiths (see workspace.ts). Settings writes go load → mutate →
 *  saveSettings, then clearAgentCache() so resolvers don't serve stale adapters. */

import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { listAgents, getDefaultAgentId, clearAgentCache } from '@/lib/agents';
import type { AgentConfig } from '@/lib/agents/types';
import { loadSettings, saveSettings } from '@/lib/settings';
import { text, fail, guard } from './_shared';

const SCENES = ['terminal', 'task', 'telegram', 'help', 'mobile'] as const;

/** Fuzzy-resolve a user-typed agent name ("claude", "claude code", "Codex") to a
 *  real agent. Matches id, then cliType/name (whitespace/hyphen-insensitive). */
function resolveAgent(input: string): AgentConfig | undefined {
  const agents = listAgents();
  const norm = (s: string) => s.toLowerCase().replace(/[\s-]+/g, '');
  const q = norm(input);
  return agents.find((a) => a.id.toLowerCase() === input.toLowerCase())
    || agents.find((a) => norm(a.id) === q)
    || agents.find((a) => norm(a.cliType || '') === q || norm(a.name) === q)
    || agents.find((a) => norm(a.name).includes(q) || norm(a.cliType || '').includes(q));
}

/** The settings.agents `tool` discriminator for a (possibly built-in) agent. */
function toolFor(a: AgentConfig): 'claude' | 'codex' | 'aider' | 'opencode' {
  if (['claude', 'codex', 'aider', 'opencode'].includes(a.id)) return a.id as 'claude';
  if (a.cliType === 'claude-code') return 'claude';
  if (a.cliType === 'codex') return 'codex';
  if (a.cliType === 'aider') return 'aider';
  return 'claude';
}

export function registerIntegrationTools(server: McpServer): void {
  server.tool(
    'forge_list_agents',
    'List the CLI coding agents Forge can drive (claude code, codex, aider, and any custom profiles): whether each is installed and enabled, which is the current default, and any per-component model overrides. Use this to answer "is Claude integrated?".',
    {},
    () => guard(() => {
      const agents = listAgents();
      const def = getDefaultAgentId();
      const settings = loadSettings();
      const lines = agents.map((a) => {
        const installed = a.path ? `installed` : 'NOT installed';
        const models = settings.agents?.[a.id]?.models || {};
        const modelStr = Object.entries(models).filter(([, v]) => v).map(([k, v]) => `${k}=${v}`).join(', ');
        return `• ${a.id} (${a.name}) [${a.cliType || a.type}] — ${installed}, ${a.enabled ? 'enabled' : 'disabled'}${a.id === def ? '  ⭐ DEFAULT' : ''}`
          + (modelStr ? `\n    models: ${modelStr}` : '');
      });
      return text(`CLI agents (default = ${def}):\n${lines.join('\n')}\n\nSet the default with forge_set_default_agent; set a component's model with forge_set_agent_model.`);
    }),
  );

  server.tool(
    'forge_set_default_agent',
    'Set the default CLI coding agent Forge uses for tasks and pipelines (e.g. "claude" / "claude code", "codex"). Accepts a fuzzy name and validates it exists.',
    { agent: z.string().describe('Agent name or id, e.g. "claude", "claude code", "codex"') },
    (params) => guard(() => {
      const match = resolveAgent(params.agent);
      if (!match) return fail(`No agent matches "${params.agent}". Available: ${listAgents().map((a) => a.id).join(', ')}.`);
      const s = loadSettings();
      s.defaultAgent = match.id;
      saveSettings(s);
      clearAgentCache();
      const warn = match.path ? '' : `\n(Note: ${match.id} is not currently installed — install it for tasks to run.)`;
      return text(`Default agent set to ${match.id} (${match.name}).${warn}`);
    }),
  );

  server.tool(
    'forge_set_agent_model',
    'Set the model an agent uses for a specific component/scene — this is how Forge runs different models for different components. Scenes: task, terminal, telegram, help, mobile. Use model "default" to clear an override.',
    {
      agent: z.string().describe('Agent name or id (e.g. "claude")'),
      scene: z.enum(SCENES).describe('Which component the model applies to'),
      model: z.string().describe('Model id (e.g. "claude-opus-4-8"), or "default" to clear'),
    },
    (params) => guard(() => {
      const match = resolveAgent(params.agent);
      if (!match) return fail(`No agent matches "${params.agent}". Available: ${listAgents().map((a) => a.id).join(', ')}.`);
      const s = loadSettings();
      const entry = s.agents?.[match.id] ? { ...s.agents[match.id] } : { tool: toolFor(match) };
      if (!entry.tool) entry.tool = toolFor(match);
      entry.models = { ...(entry.models || {}), [params.scene]: params.model };
      s.agents = { ...(s.agents || {}), [match.id]: entry };
      saveSettings(s);
      clearAgentCache();
      return text(`Set ${match.id} ${params.scene} model to "${params.model}".`);
    }),
  );
}
