#!/usr/bin/env node

import { HeadlessExecutor } from './headless-executor';
import { SessionManager } from './session-manager';
import { ResultFormatter } from './result-formatter';
import { DelegationValidator } from '../utils/delegation-validator';
import { SettingsParser } from './settings-parser';
import { fail, warn } from '../utils/ui';
import { getCcsDir } from '../utils/config-manager';

/**
 * Parse and validate a string flag value
 * @returns value if valid, undefined if invalid/missing
 */
function parseStringFlag(
  args: string[],
  flagName: string,
  options?: { allowDashPrefix?: boolean }
): string | undefined {
  const index = args.indexOf(flagName);
  if (index === -1 || index >= args.length - 1) return undefined;

  const value = args[index + 1];

  // Reject dash-prefixed values (likely another flag)
  if (!options?.allowDashPrefix && value.startsWith('-')) {
    console.error(warn(`${flagName} value "${value}" looks like a flag. Ignoring.`));
    return undefined;
  }

  // Reject empty/whitespace-only
  if (!value.trim()) {
    console.error(warn(`${flagName} value is empty. Ignoring.`));
    return undefined;
  }

  return value;
}

interface ParsedArgs {
  profile: string;
  prompt: string;
  options: {
    cwd: string;
    outputFormat: string;
    permissionMode: string;
    timeout?: number;
    resumeSession?: boolean;
    sessionId?: string;
    // Claude Code CLI passthrough flags (explicit)
    maxTurns?: number;
    fallbackModel?: string;
    agents?: string;
    betas?: string;
    extraArgs?: string[]; // Catch-all for new/unknown flags
  };
}

/**
 * Delegation command handler
 * Routes -p flag commands to HeadlessExecutor with enhanced features
 */
export class DelegationHandler {
  /**
   * Route delegation command
   * @param args - Full args array from ccs.js
   */
  async route(args: string[]): Promise<void> {
    try {
      // 1. Parse args into { profile, prompt, options }
      const parsed = this._parseArgs(args);

      // 2. Detect special profiles (glm:continue, kimi:continue)
      if (parsed.profile.includes(':continue')) {
        return await this._handleContinue(parsed);
      }

      // 3. Validate profile
      this._validateProfile(parsed.profile);

      // 4. Execute via HeadlessExecutor
      const result = await HeadlessExecutor.execute(parsed.profile, parsed.prompt, parsed.options);

      // 5. Format and display results
      const formatted = await ResultFormatter.format(result);
      console.log(formatted);

      // 6. Exit with proper code
      process.exit(result.exitCode || 0);
    } catch (error) {
      console.error(fail(`Delegation error: ${(error as Error).message}`));
      if (process.env.CCS_DEBUG) {
        console.error((error as Error).stack);
      }
      process.exit(1);
    }
  }

  /**
   * Handle continue command (resume last session)
   * @param parsed - Parsed args
   */
  async _handleContinue(parsed: ParsedArgs): Promise<void> {
    const baseProfile = parsed.profile.replace(':continue', '');

    // Get last session from SessionManager
    const sessionMgr = new SessionManager();
    const lastSession = sessionMgr.getLastSession(baseProfile);

    if (!lastSession) {
      console.error(fail(`No previous session found for ${baseProfile}`));
      console.error(`    Start a new session first with: ccs ${baseProfile} -p "task"`);
      process.exit(1);
    }

    // Execute with resume flag
    const result = await HeadlessExecutor.execute(baseProfile, parsed.prompt, {
      ...parsed.options,
      resumeSession: true,
      sessionId: lastSession.sessionId,
    });

    const formatted = await ResultFormatter.format(result);
    console.log(formatted);

    process.exit(result.exitCode || 0);
  }

  /**
   * Parse args into structured format
   * @param args - Raw args
   * @returns { profile, prompt, options }
   */
  _parseArgs(args: string[]): ParsedArgs {
    // Extract profile (first non-flag arg or 'default')
    const profile = this._extractProfile(args);

    // Extract prompt from -p or --prompt
    const prompt = this._extractPrompt(args);

    // Extract options (--timeout, --permission-mode, etc.)
    const options = this._extractOptions(args);

    return { profile, prompt, options };
  }

  /**
   * Extract profile from args (first non-flag arg)
   * @param args - Args array
   * @returns profile name
   */
  _extractProfile(args: string[]): string {
    // Find first arg that doesn't start with '-' and isn't -p value
    let skipNext = false;
    for (let i = 0; i < args.length; i++) {
      if (skipNext) {
        skipNext = false;
        continue;
      }

      if (args[i] === '-p' || args[i] === '--prompt') {
        skipNext = true;
        continue;
      }

      if (!args[i].startsWith('-')) {
        return args[i];
      }
    }

    // No profile specified, return empty string (will error in validation)
    return '';
  }

  /**
   * Extract prompt from -p flag
   * @param args - Args array
   * @returns prompt text
   */
  _extractPrompt(args: string[]): string {
    const pIndex = args.indexOf('-p');
    const promptIndex = args.indexOf('--prompt');

    const index = pIndex !== -1 ? pIndex : promptIndex;

    if (index === -1 || index === args.length - 1) {
      console.error(fail('Missing prompt after -p flag'));
      console.error('    Usage: ccs glm -p "task description"');
      process.exit(1);
    }

    return args[index + 1];
  }

  /**
   * Extract options from remaining args
   * @param args - Args array
   * @returns options for HeadlessExecutor
   */
  _extractOptions(args: string[]): ParsedArgs['options'] {
    const cwd = process.cwd();

    // Read default permission mode from .claude/settings.local.json
    // Falls back to 'acceptEdits' if file doesn't exist
    const defaultPermissionMode = SettingsParser.parseDefaultPermissionMode(cwd);

    const options: ParsedArgs['options'] = {
      cwd,
      outputFormat: 'stream-json',
      permissionMode: defaultPermissionMode,
    };

    // Parse permission-mode (CLI flag overrides settings file)
    const permModeIndex = args.indexOf('--permission-mode');
    if (permModeIndex !== -1 && permModeIndex < args.length - 1) {
      options.permissionMode = args[permModeIndex + 1];
    }

    // Parse timeout (validated: positive integer, max 10 minutes)
    const timeoutIndex = args.indexOf('--timeout');
    if (timeoutIndex !== -1 && timeoutIndex < args.length - 1) {
      const rawVal = args[timeoutIndex + 1];
      const val = parseInt(rawVal, 10);
      if (!isNaN(val) && val > 0 && val <= 600000) {
        options.timeout = val;
      } else if (isNaN(val)) {
        console.error(warn(`--timeout "${rawVal}" is not a number. Using default.`));
      } else if (val <= 0) {
        console.error(warn(`--timeout ${val} must be positive. Using default.`));
      } else if (val > 600000) {
        console.error(warn(`--timeout ${val} exceeds max (600000ms). Using default.`));
      }
    }

    // Parse --max-turns (limit agentic turns, max 100)
    const maxTurnsIndex = args.indexOf('--max-turns');
    if (maxTurnsIndex !== -1 && maxTurnsIndex < args.length - 1) {
      const rawVal = args[maxTurnsIndex + 1];
      const val = parseInt(rawVal, 10);
      if (!isNaN(val) && val > 0 && val <= 100) {
        options.maxTurns = val;
      } else if (isNaN(val)) {
        console.error(warn(`--max-turns "${rawVal}" is not a number. Ignoring.`));
      } else if (val <= 0) {
        console.error(warn(`--max-turns ${val} must be positive. Ignoring.`));
      } else if (val > 100) {
        console.error(warn(`--max-turns ${val} exceeds max (100). Using 100.`));
        options.maxTurns = 100;
      }
    }

    // Parse --fallback-model (auto-fallback on overload)
    options.fallbackModel = parseStringFlag(args, '--fallback-model');

    // Parse --agents (dynamic subagent JSON)
    const agentsValue = parseStringFlag(args, '--agents');
    if (agentsValue) {
      // Validate JSON structure
      try {
        JSON.parse(agentsValue);
        options.agents = agentsValue;
      } catch {
        console.error(warn('--agents must be valid JSON. Ignoring.'));
      }
    }

    // Parse --betas (experimental features)
    options.betas = parseStringFlag(args, '--betas');

    // Collect extra args to pass through to Claude CLI
    // CCS-handled flags with values (skip these and their values):
    const ccsFlagsWithValue = new Set([
      '-p',
      '--prompt',
      '--timeout',
      '--permission-mode',
      '--max-turns',
      '--fallback-model',
      '--agents',
      '--betas',
    ]);
    const extraArgs: string[] = [];
    const profile = this._extractProfile(args);

    for (let i = 0; i < args.length; i++) {
      const arg = args[i];

      // Skip profile name (non-flag first arg)
      if (arg === profile && !arg.startsWith('-')) continue;

      // Skip CCS-handled flags and their values
      if (ccsFlagsWithValue.has(arg)) {
        i++; // Skip next arg (the value)
        continue;
      }

      // Collect flags and their values as passthrough
      if (arg.startsWith('-')) {
        extraArgs.push(arg);
        // If next arg exists and doesn't start with '-', it's likely a value
        if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
          extraArgs.push(args[i + 1]);
          i++; // Skip the value we just added
        }
      }
    }

    if (extraArgs.length > 0) {
      options.extraArgs = extraArgs;
    }

    return options;
  }

  /**
   * Validate profile exists and is configured
   * @param profile - Profile name
   */
  _validateProfile(profile: string): void {
    if (!profile) {
      console.error(fail('No profile specified'));
      console.error('    Usage: ccs <profile> -p "task"');
      console.error('    Examples: ccs glm -p "task", ccs km -p "task"');
      process.exit(1);
    }

    // Use DelegationValidator to check profile
    const validation = DelegationValidator.validate(profile);
    if (!validation.valid) {
      console.error(fail(`Profile '${profile}' is not configured for delegation`));
      console.error(`    ${validation.error}`);
      console.error('');
      console.error('    Run: ccs doctor');
      console.error(`    Or configure: ${getCcsDir()}/${profile}.settings.json`);
      process.exit(1);
    }
  }
}
