/**
 * Setup Command Handler
 *
 * Interactive first-time setup wizard for CCS.
 * Guides users through initial configuration including:
 * - Local vs Remote CLIProxy mode selection
 * - Remote proxy configuration (host, port, auth token)
 * - Default profile selection
 *
 * Usage: ccs setup
 *
 * Related: Issue #142 - remote CLIProxyAPI configuration
 */

import * as readline from 'readline';
import * as fs from 'fs';
import * as path from 'path';
import { initUI, header, ok, info, warn } from '../utils/ui';
import {
  loadOrCreateUnifiedConfig,
  loadUnifiedConfig,
  mutateUnifiedConfig,
  hasUnifiedConfig,
} from '../config/unified-config-loader';
import { DEFAULT_CLIPROXY_SERVER_CONFIG } from '../config/unified-config-types';
import { getCcsDir } from '../utils/config-manager';
import { CLIPROXY_DEFAULT_PORT } from '../cliproxy/config/port-manager';

/** Custom error for user cancellation (Ctrl+C) */
class UserCancelledError extends Error {
  constructor() {
    super('Setup cancelled by user');
    this.name = 'UserCancelledError';
  }
}

/**
 * Create readline interface for interactive prompts
 */
function createReadline(): readline.Interface {
  return readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
}

/**
 * Prompt user for input with optional default value
 * Handles Ctrl+C gracefully by rejecting with UserCancelledError
 */
async function prompt(
  rl: readline.Interface,
  question: string,
  defaultValue?: string
): Promise<string> {
  return new Promise((resolve, reject) => {
    const displayQuestion = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;

    const onClose = () => {
      reject(new UserCancelledError());
    };

    rl.once('close', onClose);
    rl.question(displayQuestion, (answer) => {
      rl.removeListener('close', onClose);
      resolve(answer.trim() || defaultValue || '');
    });
  });
}

/**
 * Prompt user for yes/no confirmation
 */
async function confirm(
  rl: readline.Interface,
  question: string,
  defaultYes: boolean = true
): Promise<boolean> {
  const hint = defaultYes ? '[Y/n]' : '[y/N]';
  const answer = await prompt(rl, `${question} ${hint}`);

  if (answer === '') return defaultYes;
  return answer.toLowerCase().startsWith('y');
}

/**
 * Prompt user to select from numbered options
 */
async function selectOption(
  rl: readline.Interface,
  question: string,
  options: { label: string; value: string; description?: string }[]
): Promise<string> {
  console.log('');
  console.log(question);
  console.log('');

  options.forEach((opt, idx) => {
    const desc = opt.description ? ` - ${opt.description}` : '';
    console.log(`  ${idx + 1}) ${opt.label}${desc}`);
  });

  console.log('');
  const answer = await prompt(rl, 'Enter choice (number)', '1');
  const idx = parseInt(answer, 10) - 1;

  if (idx >= 0 && idx < options.length) {
    return options[idx].value;
  }

  // Invalid selection, default to first
  console.log(warn(`Invalid selection, using default: ${options[0].label}`));
  return options[0].value;
}

/**
 * Check if this is a first-time install (config exists but is empty/unconfigured).
 * Returns true if user should be prompted to run setup wizard.
 *
 * Detection priority:
 * 1. setup_completed flag (explicit wizard completion)
 * 2. Unified config content (profiles, accounts, variants, oauth_accounts, remote proxy)
 * 3. Legacy config.json profiles (GLM, Kimi)
 * 4. Legacy profiles.json accounts
 */
export function isFirstTimeInstall(): boolean {
  // Check unified config first (config.yaml)
  if (hasUnifiedConfig()) {
    const loaded = loadUnifiedConfig();

    // Config exists but is corrupted/invalid - don't treat as first-time
    if (loaded === null) {
      console.log(warn('Warning: ~/.ccs/config.yaml exists but appears corrupted'));
      console.log(info('  Run `ccs setup --force` to reset, or `ccs doctor` to diagnose'));
      return false;
    }

    // If setup wizard was completed, NOT first-time install
    if (loaded.setup_completed) {
      return false;
    }

    // Check for any meaningful configuration in unified config
    const hasProfiles = Object.keys(loaded.profiles || {}).length > 0;
    const hasAccounts = Object.keys(loaded.accounts || {}).length > 0;
    const hasVariants = Object.keys(loaded.cliproxy?.variants || {}).length > 0;
    const hasOAuthAccounts = Object.keys(loaded.cliproxy?.oauth_accounts || {}).length > 0;
    const hasRemoteProxy =
      loaded.cliproxy_server?.remote?.enabled && loaded.cliproxy_server?.remote?.host;

    // If any of these exist in unified config, user has configured something
    if (hasProfiles || hasAccounts || hasVariants || hasOAuthAccounts || hasRemoteProxy) {
      return false;
    }
  }

  // Also check legacy config.json for existing profiles
  // This prevents treating users with GLM/Kimi in config.json as "first-time installs"
  const ccsDir = getCcsDir();
  const legacyConfigPath = path.join(ccsDir, 'config.json');

  if (fs.existsSync(legacyConfigPath)) {
    try {
      const content = fs.readFileSync(legacyConfigPath, 'utf8');
      const legacyConfig = JSON.parse(content) as { profiles?: Record<string, string> };

      if (legacyConfig.profiles && Object.keys(legacyConfig.profiles).length > 0) {
        // Has legacy profiles - NOT first time
        return false;
      }
    } catch {
      // Legacy config exists but is invalid - ignore and continue
    }
  }

  // Also check profiles.json for existing accounts
  const legacyProfilesPath = path.join(ccsDir, 'profiles.json');

  if (fs.existsSync(legacyProfilesPath)) {
    try {
      const content = fs.readFileSync(legacyProfilesPath, 'utf8');
      const legacyProfiles = JSON.parse(content) as { profiles?: Record<string, unknown> };

      if (legacyProfiles.profiles && Object.keys(legacyProfiles.profiles).length > 0) {
        // Has legacy accounts - NOT first time
        return false;
      }
    } catch {
      // Legacy profiles exists but is invalid - ignore and continue
    }
  }

  // No meaningful configuration found anywhere
  return true;
}

/**
 * Configure remote CLIProxy settings interactively
 */
async function configureRemoteProxy(rl: readline.Interface): Promise<{
  host: string;
  port?: number;
  protocol: 'http' | 'https';
  authToken: string;
}> {
  console.log('');
  console.log(info('Configure Remote CLIProxyAPI Connection'));
  console.log('');
  console.log('  Enter the details for your remote CLIProxyAPI server.');
  console.log('  Example: your-server.example.com');
  console.log('');

  // Host - with protocol stripping
  let host = await prompt(rl, 'Remote host (hostname or IP)');
  if (!host) {
    throw new Error('Host is required for remote proxy mode');
  }
  // Strip protocol if user included it (common mistake)
  host = host.replace(/^https?:\/\//, '');
  // Strip trailing slashes
  host = host.replace(/\/+$/, '');

  // Protocol
  const protocol = (await selectOption(rl, 'Protocol:', [
    { label: 'HTTPS', value: 'https', description: 'Secure connection (recommended)' },
    { label: 'HTTP', value: 'http', description: 'Unencrypted connection' },
  ])) as 'http' | 'https';

  // Port (optional) - with validation
  const defaultPort = protocol === 'https' ? '443' : String(CLIPROXY_DEFAULT_PORT);
  const portStr = await prompt(rl, `Port (leave empty for default ${defaultPort})`);
  let port: number | undefined;
  if (portStr) {
    const parsed = parseInt(portStr, 10);
    if (isNaN(parsed) || parsed < 1 || parsed > 65535 || !Number.isInteger(parsed)) {
      console.log(warn(`Invalid port "${portStr}", using default: ${defaultPort}`));
      port = undefined; // Use default
    } else {
      port = parsed;
    }
  }

  // Auth token
  console.log('');
  console.log(info('Authentication'));
  console.log('  The auth token is configured in your CLIProxyAPI config.yaml');
  console.log('  under api-keys section. Example: "ccs-internal-managed"');
  console.log('');

  const authToken = await prompt(rl, 'Auth token', 'ccs-internal-managed');

  return { host, port, protocol, authToken };
}

/**
 * Main setup wizard
 */
async function runSetupWizard(force: boolean = false): Promise<void> {
  const rl = createReadline();

  try {
    console.log('');
    console.log(header('CCS First-Time Setup'));
    console.log('');

    // Check if already configured
    if (!force && !isFirstTimeInstall()) {
      console.log(info('CCS is already configured.'));
      console.log('  Use --force to reconfigure, or run `ccs config` for the dashboard.');
      console.log('');
      rl.close();
      return;
    }

    console.log('Welcome to CCS (Claude Code Switch)!');
    console.log('This wizard will help you configure CCS for first-time use.');
    console.log('');

    // Step 1: Local vs Remote mode
    const proxyMode = await selectOption(
      rl,
      'How do you want to use CLIProxy providers (gemini, codex, agy)?',
      [
        {
          label: 'Local (Recommended)',
          value: 'local',
          description: 'CCS auto-starts CLIProxyAPI binary on your machine',
        },
        {
          label: 'Remote Server',
          value: 'remote',
          description: 'Connect to a remote CLIProxyAPI instance (Issue #142)',
        },
        {
          label: 'Skip CLIProxy',
          value: 'skip',
          description: 'Only use API profiles (GLM, Kimi) or Claude accounts',
        },
      ]
    );

    // Load or create config
    const config = loadOrCreateUnifiedConfig();

    if (proxyMode === 'remote') {
      // Configure remote proxy
      const remoteConfig = await configureRemoteProxy(rl);

      config.cliproxy_server = {
        remote: {
          enabled: true,
          host: remoteConfig.host,
          port: remoteConfig.port,
          protocol: remoteConfig.protocol,
          auth_token: remoteConfig.authToken,
        },
        fallback: {
          enabled: true,
          auto_start: false,
        },
        local: {
          port: CLIPROXY_DEFAULT_PORT,
          auto_start: false, // Disable local auto-start when using remote
        },
      };

      console.log('');
      console.log(ok('Remote proxy configured successfully!'));
      console.log('');
      console.log(
        `  URL: ${remoteConfig.protocol}://${remoteConfig.host}${remoteConfig.port ? `:${remoteConfig.port}` : ''}`
      );
      console.log(`  Auth: ${remoteConfig.authToken ? '[configured]' : '[none]'}`);
    } else if (proxyMode === 'local') {
      // Ensure local mode is configured
      config.cliproxy_server = {
        ...DEFAULT_CLIPROXY_SERVER_CONFIG,
        remote: {
          enabled: false,
          host: '',
          protocol: 'http',
          auth_token: '',
        },
        local: {
          port: CLIPROXY_DEFAULT_PORT,
          auto_start: true,
        },
      };

      console.log('');
      console.log(ok('Local proxy mode configured!'));
      console.log('  CLIProxyAPI will auto-start when you use gemini/codex/agy profiles.');
    } else {
      // Skip CLIProxy - just use local config
      console.log('');
      console.log(ok('CLIProxy skipped.'));
      console.log('  You can still use API profiles (GLM, Kimi) or Claude accounts.');
    }

    // Step 2: Ask about API profiles
    console.log('');
    const wantsApiProfile = await confirm(
      rl,
      'Do you want to set up an API profile (GLM, Kimi, custom)?',
      false
    );

    if (wantsApiProfile) {
      console.log('');
      console.log(info('Creating API profiles...'));
      console.log('  Use the following commands to create profiles:');
      console.log('');
      console.log('    ccs api create glm --preset glm');
      console.log('    ccs api create km --preset km');
      console.log('    ccs api create custom --prompt');
      console.log('');
      console.log('  After creating, edit the settings file to add your API key.');
    }

    mutateUnifiedConfig((currentConfig) => {
      currentConfig.setup_completed = true;
      currentConfig.cliproxy_server = config.cliproxy_server;
    });

    // Final summary
    console.log('');
    console.log(header('Setup Complete!'));
    console.log('');
    console.log('Quick start commands:');
    console.log('');

    if (proxyMode !== 'skip') {
      console.log('  ccs gemini          # Use Gemini via CLIProxy (OAuth)');
      console.log('  ccs codex           # Use Codex via CLIProxy (OAuth)');
      console.log('  ccs agy             # Use Antigravity via CLIProxy (OAuth)');
    }

    console.log('  ccs                 # Use default Claude CLI');
    console.log('  ccs config          # Open web dashboard');
    console.log('  ccs doctor          # Check configuration health');
    console.log('');

    if (proxyMode === 'remote') {
      console.log(info('Remote proxy tip:'));
      console.log('  If connection fails, CCS will offer to start local proxy as fallback.');
      console.log('  Edit ~/.ccs/config.yaml to adjust remote settings.');
      console.log('');
    }

    console.log(info('Configuration saved to: ~/.ccs/config.yaml'));
    console.log('');
  } catch (err) {
    // Handle user cancellation gracefully
    if (err instanceof UserCancelledError) {
      console.log('');
      console.log(info('Setup cancelled.'));
      console.log('  Run `ccs setup` when ready to configure.');
      console.log('');
      return;
    }
    // Handle other errors with user-friendly message
    const message = err instanceof Error ? err.message : String(err);
    console.log('');
    console.log(warn(`Setup failed: ${message}`));
    console.log(info('  Run `ccs setup` to try again.'));
    console.log('');
  } finally {
    rl.close();
  }
}

/**
 * Parse command line arguments
 */
function parseArgs(args: string[]): { force: boolean; help: boolean } {
  return {
    force: args.includes('--force') || args.includes('-f'),
    help: args.includes('--help') || args.includes('-h'),
  };
}

/**
 * Show help message
 */
function showHelp(): void {
  console.log('');
  console.log('Usage: ccs setup [options]');
  console.log('');
  console.log('Interactive first-time setup wizard for CCS.');
  console.log('');
  console.log('Options:');
  console.log('  --force, -f     Force setup even if already configured');
  console.log('  --help, -h      Show this help message');
  console.log('');
  console.log('This wizard helps you configure:');
  console.log('  - Local vs Remote CLIProxy mode');
  console.log('  - Remote proxy connection (host, port, auth token)');
  console.log('  - API profile creation');
  console.log('');
  console.log('Examples:');
  console.log('  ccs setup           Run setup wizard');
  console.log('  ccs setup --force   Force reconfiguration');
  console.log('');
}

/**
 * Handle setup command
 */
export async function handleSetupCommand(args: string[]): Promise<void> {
  await initUI();

  const options = parseArgs(args);

  if (options.help) {
    showHelp();
    return;
  }

  await runSetupWizard(options.force);
}
