/**
 * Agent command - Interactive AI coding assistant.
 */

import { Command } from 'commander';
import { EmdashClient } from '../client.js';
import { SSERenderer } from '../sse-renderer.js';
import { getServerManager } from '../server-manager.js';
import { style, LOGO_MINIMAL } from '../design.js';
import type { CLIOptions } from '../types.js';

export const agentCommand = new Command('agent')
  .description('AI agent commands')
  .addCommand(
    new Command('code')
      .description('Start the coding agent')
      .argument('[task]', 'Task to perform')
      .option('-m, --model <model>', 'Model to use')
      .option('--mode <mode>', 'Starting mode (plan, tasks, code)', 'code')
      .option('-q, --quiet', 'Less verbose output')
      .option('--max-iterations <n>', 'Max agent iterations', '100')
      .option('--no-graph-tools', 'Skip graph exploration tools')
      .option('--save', 'Save specs to specs/<feature>/')
      .action(async (task: string | undefined, options: CLIOptions) => {
        await runCodingAgent(task, options);
      })
  )
  .addCommand(
    new Command('sessions')
      .description('List active sessions')
      .action(async () => {
        const manager = getServerManager();
        const url = await manager.ensureServer();
        const client = new EmdashClient(url);

        try {
          const sessions = await client.listSessions();
          if (sessions.length === 0) {
            console.log('No active sessions');
            return;
          }

          console.log('Active sessions:');
          for (const session of sessions) {
            console.log(`  ${session.session_id} - ${session.status} (${session.message_count} messages)`);
          }
        } catch (error) {
          console.error('Failed to list sessions:', (error as Error).message);
          process.exit(1);
        }
      })
  );

/**
 * Direct entry point for `em-ts` command.
 */
export async function startCodingAgent(args: string[]): Promise<void> {
  const program = new Command()
    .name('em-ts')
    .description('EmDash Coding Agent - AI-powered code assistant.')
    .argument('[task]', 'Task to perform')
    .option('-m, --model <model>', 'Model to use')
    .option('--mode <mode>', 'Starting mode (plan, tasks, code)', 'code')
    .option('-q, --quiet', 'Less verbose output')
    .option('--max-iterations <n>', 'Max agent iterations', '100')
    .option('--no-graph-tools', 'Skip graph exploration tools')
    .option('--save', 'Save specs to specs/<feature>/')
    .action(async (task: string | undefined, options: CLIOptions) => {
      await runCodingAgent(task, options);
    });

  await program.parseAsync(['node', 'em-ts', ...args]);
}

async function runCodingAgent(task: string | undefined, options: CLIOptions): Promise<void> {
  const manager = getServerManager();
  const url = await manager.ensureServer();
  const client = new EmdashClient(url);
  const renderer = new SSERenderer(!options.quiet);

  // Show welcome message
  if (!options.quiet) {
    console.log();
    console.log(`  ${style.primary(LOGO_MINIMAL)}`);
    console.log();
  }

  // Interactive mode if no task provided
  if (!task) {
    await interactiveMode(client, renderer, options);
    return;
  }

  // Single task mode
  await runSingleTask(client, renderer, task, options);
}

async function runSingleTask(
  client: EmdashClient,
  renderer: SSERenderer,
  task: string,
  options: CLIOptions
): Promise<void> {
  const maxIterations = parseInt(options.maxIterations?.toString() ?? '100', 10);

  const stream = client.agentChatStream(
    task,
    options.model,
    undefined,
    maxIterations,
    {
      mode: options.mode,
      save: options.save,
      no_graph_tools: options.noGraphTools,
      verbose: !options.quiet,
    }
  );

  const result = await renderer.renderStream(stream);

  // Handle clarification
  if (result.clarification) {
    console.log('\nClarification needed. Run in interactive mode for full support.');
  }

  // Handle plan
  if (result.plan_submitted) {
    console.log('\nPlan submitted. Run in interactive mode to approve/reject.');
  }
}

async function interactiveMode(
  client: EmdashClient,
  renderer: SSERenderer,
  options: CLIOptions
): Promise<void> {
  const readline = await import('node:readline');
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  let sessionId: string | undefined;
  const maxIterations = parseInt(options.maxIterations?.toString() ?? '100', 10);

  const promptUser = (): Promise<string> => {
    return new Promise((resolve) => {
      const prompt = options.mode === 'plan'
        ? `${style.warning('plan')} ${style.success('›')} `
        : `${style.success('›')} `;
      rl.question(prompt, (answer) => {
        resolve(answer);
      });
    });
  };

  console.log('Interactive mode. Type your task or /help for commands.');
  console.log();

  while (true) {
    const input = await promptUser();
    const trimmedInput = input.trim();

    if (!trimmedInput) continue;

    // Handle commands
    if (trimmedInput.startsWith('/')) {
      const handled = await handleCommand(trimmedInput, client, sessionId);
      if (handled === 'exit') {
        break;
      }
      continue;
    }

    // Run task
    let stream: AsyncGenerator<string, void, unknown>;

    if (sessionId) {
      stream = client.agentContinueStream(sessionId, trimmedInput);
    } else {
      stream = client.agentChatStream(
        trimmedInput,
        options.model,
        undefined,
        maxIterations,
        {
          mode: options.mode,
          save: options.save,
          no_graph_tools: options.noGraphTools,
          verbose: !options.quiet,
        }
      );
    }

    const result = await renderer.renderStream(stream);
    sessionId = result.session_id ?? sessionId;

    // Handle clarification
    if (result.clarification) {
      const answer = await promptUser();
      if (answer && sessionId) {
        const clarificationStream = client.clarificationAnswerStream(sessionId, answer);
        const clarificationResult = await renderer.renderStream(clarificationStream);
        sessionId = clarificationResult.session_id ?? sessionId;
      }
    }

    // Handle plan approval
    if (result.plan_submitted && sessionId) {
      console.log('\nApprove plan? (y/n/feedback): ');
      const answer = await promptUser();

      if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
        const approveStream = client.planApproveStream(sessionId);
        await renderer.renderStream(approveStream);
      } else if (answer.toLowerCase() !== 'n' && answer.toLowerCase() !== 'no') {
        const rejectStream = client.planRejectStream(sessionId, answer);
        await renderer.renderStream(rejectStream);
      }
    }

    // Handle plan mode request
    if (result.plan_mode_requested && sessionId) {
      console.log('\nAllow plan mode? (y/n): ');
      const answer = await promptUser();

      if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
        const approveStream = client.planmodeApproveStream(sessionId);
        await renderer.renderStream(approveStream);
      } else {
        const rejectStream = client.planmodeRejectStream(sessionId);
        await renderer.renderStream(rejectStream);
      }
    }

    console.log();
  }

  rl.close();
}

async function handleCommand(
  command: string,
  client: EmdashClient,
  sessionId: string | undefined
): Promise<string | undefined> {
  const parts = command.slice(1).split(/\s+/);
  const cmd = parts[0]?.toLowerCase();

  switch (cmd) {
    case 'help':
      console.log(`
Commands:
  /help      - Show this help message
  /exit      - Exit interactive mode
  /quit      - Exit interactive mode
  /sessions  - List active sessions
  /clear     - Start a new session
  /model     - Show or set the model
`);
      break;

    case 'exit':
    case 'quit':
      console.log('Goodbye!');
      return 'exit';

    case 'sessions':
      try {
        const sessions = await client.listSessions();
        if (sessions.length === 0) {
          console.log('No active sessions');
        } else {
          console.log('Active sessions:');
          for (const session of sessions) {
            const current = session.session_id === sessionId ? ' (current)' : '';
            console.log(`  ${session.session_id}${current} - ${session.status}`);
          }
        }
      } catch (error) {
        console.error('Failed to list sessions:', (error as Error).message);
      }
      break;

    case 'clear':
      console.log('Starting new session...');
      return undefined;

    default:
      console.log(`Unknown command: ${cmd}`);
      console.log('Type /help for available commands.');
  }

  return undefined;
}
