import type { Command } from 'commander';
import { registerFleetAgentCommands, type FleetCommandDeps } from './fleet.js';
import { withAuth } from './with-auth.js';
import { selectItem } from './select-dialog.js';
import {
  fetchAgentConfigs,
  createAgentConfig,
  updateAgentConfig,
  deleteAgentConfig,
  fetchProjects,
  fetchProviders,
} from '../tui/gateway-api.js';
import type { AgentConfigInfo } from '../tui/gateway-api.js';

function formatAgent(a: AgentConfigInfo): string {
  const sys = a.isSystem ? ' [system]' : '';
  return `${a.name}${sys} — ${a.provider}/${a.model} (${a.status})`;
}

function showAgentDetail(a: AgentConfigInfo) {
  console.log(`  ID:           ${a.id}`);
  console.log(`  Name:         ${a.name}`);
  console.log(`  Provider:     ${a.provider}`);
  console.log(`  Model:        ${a.model}`);
  console.log(`  Status:       ${a.status}`);
  console.log(`  System:       ${a.isSystem ? 'yes' : 'no'}`);
  console.log(`  Project:      ${a.projectId ?? '—'}`);
  console.log(`  System Prompt: ${a.systemPrompt ? `${a.systemPrompt.slice(0, 80)}...` : '—'}`);
  console.log(`  Tools:        ${a.allowedTools ? a.allowedTools.join(', ') : 'all'}`);
  console.log(`  Skills:       ${a.skills ? a.skills.join(', ') : '—'}`);
  console.log(`  Created:      ${new Date(a.createdAt).toLocaleString()}`);
}

export function registerAgentCommand(program: Command, fleetDeps: FleetCommandDeps = {}) {
  const cmd = program
    .command('agent')
    .description('Manage agent configurations and local fleet agents')
    .option('-g, --gateway <url>', 'Gateway URL', 'http://localhost:14242')
    .option('--mosaic-home <path>', 'Mosaic home directory')
    .option('--roster <path>', 'Local fleet roster path')
    .option('--list', 'List all agents')
    .option('--new', 'Create a new agent')
    .option('--show <idOrName>', 'Show agent details')
    .option('--update <idOrName>', 'Update an agent')
    .option('--delete <idOrName>', 'Delete an agent')
    .action(
      async (opts: {
        gateway: string;
        list?: boolean;
        new?: boolean;
        show?: string;
        update?: string;
        delete?: string;
      }) => {
        const auth = await withAuth(opts.gateway);

        if (opts.list) {
          return listAgents(auth.gateway, auth.cookie);
        }
        if (opts.new) {
          return createAgentWizard(auth.gateway, auth.cookie);
        }
        if (opts.show) {
          return showAgent(auth.gateway, auth.cookie, opts.show);
        }
        if (opts.update) {
          return updateAgentWizard(auth.gateway, auth.cookie, opts.update);
        }
        if (opts.delete) {
          return deleteAgent(auth.gateway, auth.cookie, opts.delete);
        }

        // Default: interactive select
        return interactiveSelect(auth.gateway, auth.cookie);
      },
    );

  registerFleetAgentCommands(cmd, fleetDeps);

  return cmd;
}

async function resolveAgent(
  gateway: string,
  cookie: string,
  idOrName: string,
): Promise<AgentConfigInfo | undefined> {
  const agents = await fetchAgentConfigs(gateway, cookie);
  return agents.find((a) => a.id === idOrName || a.name === idOrName);
}

async function listAgents(gateway: string, cookie: string) {
  const agents = await fetchAgentConfigs(gateway, cookie);
  if (agents.length === 0) {
    console.log('No agents found.');
    return;
  }
  console.log(`Agents (${agents.length}):\n`);
  for (const a of agents) {
    const sys = a.isSystem ? ' [system]' : '';
    const project = a.projectId ? ` project=${a.projectId.slice(0, 8)}` : '';
    console.log(`  ${a.name}${sys}  ${a.provider}/${a.model}  ${a.status}${project}`);
  }
}

async function showAgent(gateway: string, cookie: string, idOrName: string) {
  const agent = await resolveAgent(gateway, cookie, idOrName);
  if (!agent) {
    console.error(`Agent "${idOrName}" not found.`);
    process.exit(1);
  }
  showAgentDetail(agent);
}

async function interactiveSelect(gateway: string, cookie: string) {
  const agents = await fetchAgentConfigs(gateway, cookie);
  const selected = await selectItem(agents, {
    message: 'Select an agent:',
    render: formatAgent,
    emptyMessage: 'No agents found. Create one with `mosaic agent --new`.',
  });
  if (selected) {
    showAgentDetail(selected);
  }
}

async function createAgentWizard(gateway: string, cookie: string) {
  const readline = await import('node:readline');
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
  const ask = (q: string): Promise<string> => new Promise((resolve) => rl.question(q, resolve));

  try {
    const name = await ask('Agent name: ');
    if (!name.trim()) {
      console.error('Name is required.');
      return;
    }

    // Project selection
    const projects = await fetchProjects(gateway, cookie);
    let projectId: string | undefined;
    if (projects.length > 0) {
      const selected = await selectItem(projects, {
        message: 'Assign to project (optional):',
        render: (p) => `${p.name} (${p.status})`,
      });
      if (selected) projectId = selected.id;
    }

    // Provider / model selection
    const providers = await fetchProviders(gateway, cookie);
    let provider = 'default';
    let model = 'default';

    if (providers.length > 0) {
      const allModels = providers.flatMap((p) =>
        p.models.map((m) => ({ provider: p.name, model: m.id, label: `${p.name}/${m.id}` })),
      );
      if (allModels.length > 0) {
        const selected = await selectItem(allModels, {
          message: 'Select model:',
          render: (m) => m.label,
        });
        if (selected) {
          provider = selected.provider;
          model = selected.model;
        }
      }
    }

    const systemPrompt = await ask('System prompt (optional, press Enter to skip): ');

    const agent = await createAgentConfig(gateway, cookie, {
      name: name.trim(),
      provider,
      model,
      projectId,
      systemPrompt: systemPrompt.trim() || undefined,
    });

    console.log(`\nAgent "${agent.name}" created (${agent.id}).`);
  } finally {
    rl.close();
  }
}

async function updateAgentWizard(gateway: string, cookie: string, idOrName: string) {
  const agent = await resolveAgent(gateway, cookie, idOrName);
  if (!agent) {
    console.error(`Agent "${idOrName}" not found.`);
    process.exit(1);
  }

  const readline = await import('node:readline');
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
  const ask = (q: string): Promise<string> => new Promise((resolve) => rl.question(q, resolve));

  try {
    console.log(`Updating agent: ${agent.name}\n`);

    const name = await ask(`Name [${agent.name}]: `);
    const systemPrompt = await ask(`System prompt [${agent.systemPrompt ? 'set' : 'none'}]: `);

    const updates: Record<string, unknown> = {};
    if (name.trim()) updates['name'] = name.trim();
    if (systemPrompt.trim()) updates['systemPrompt'] = systemPrompt.trim();

    if (Object.keys(updates).length === 0) {
      console.log('No changes.');
      return;
    }

    const updated = await updateAgentConfig(gateway, cookie, agent.id, updates);
    console.log(`\nAgent "${updated.name}" updated.`);
  } finally {
    rl.close();
  }
}

async function deleteAgent(gateway: string, cookie: string, idOrName: string) {
  const agent = await resolveAgent(gateway, cookie, idOrName);
  if (!agent) {
    console.error(`Agent "${idOrName}" not found.`);
    process.exit(1);
  }

  if (agent.isSystem) {
    console.error('Cannot delete system agents.');
    process.exit(1);
  }

  const readline = await import('node:readline');
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
  const answer = await new Promise<string>((resolve) =>
    rl.question(`Delete agent "${agent.name}"? (y/N): `, resolve),
  );
  rl.close();

  if (answer.toLowerCase() !== 'y') {
    console.log('Cancelled.');
    return;
  }

  await deleteAgentConfig(gateway, cookie, agent.id);
  console.log(`Agent "${agent.name}" deleted.`);
}
