/**
 * @fileoverview OrdoJS CLI - Deploy command
 */

import { Command } from 'commander';
import { AWSLambdaAdapter, DeploymentAdapterManager, NetlifyAdapter, VercelAdapter } from '../utils/deployment/index.js';
import { readFile } from '../utils/fs.js';
import { CLIError, ErrorType, logger } from '../utils/index.js';

/**
 * Register the deploy command
 */
export function registerDeployCommand(program: Command): void {
  program
    .command('deploy')
    .description('Deploy an OrdoJS application to a hosting provider')
    .option('-a, --adapter <adapter>', 'Deployment adapter (vercel, netlify, aws-lambda)', 'vercel')
    .option('-d, --dir <dir>', 'Directory to deploy', 'dist')
    .option('-c, --config <file>', 'Path to deployment configuration file')
    .option('--domain <domain>', 'Custom domain name')
    .option('--env <env>', 'Environment variables in KEY=VALUE format', collectEnvVars, {})
    .option('--static', 'Deploy as a static site', false)
    .option('--server', 'Include server functions', false)
    .option('--production', 'Deploy to production environment', false)
    .action(async (options) => {
      try {
        await deployCommand(options);
      } catch (error) {
        if (error instanceof CLIError) {
          logger.error(`${error.type.toUpperCase()} ERROR: ${error.message}`);
          if (error.code) {
            logger.error(`Error code: ${error.code}`);
          }
          if (error.suggestions && error.suggestions.length > 0) {
            logger.info('Suggestions:');
            error.suggestions.forEach(suggestion => {
              logger.info(`  - ${suggestion}`);
            });
          }
        } else {
          logger.error(`Deployment failed: ${error instanceof Error ? error.message : String(error)}`);
        }
        process.exit(1);
      }
    });
}

/**
 * Collect environment variables from command line
 */
function collectEnvVars(value: string, previous: Record<string, string>): Record<string, string> {
  const [key, val] = value.split('=');
  if (!key || !val) {
    throw new CLIError('Environment variables must be in KEY=VALUE format', ErrorType.VALIDATION, 'CLI-101', [
      'Example: --env API_KEY=123456'
    ]);
  }
  return { ...previous, [key]: val };
}

/**
 * Deploy command implementation
 */
export async function deployCommand(options: {
  adapter: string;
  dir: string;
  config?: string;
  domain?: string;
  env: Record<string, string>;
  static: boolean;
  server: boolean;
  production: boolean;
}): Promise<void> {
  logger.info(`Deploying with ${options.adapter} adapter...`);

  try {
    // Initialize deployment adapter manager
    const adapterManager = new DeploymentAdapterManager();

    // Register available adapters
    adapterManager.registerAdapter(new VercelAdapter());
    adapterManager.registerAdapter(new NetlifyAdapter());
    adapterManager.registerAdapter(new AWSLambdaAdapter());

    // Check if the specified adapter exists
    const adapter = adapterManager.getAdapter(options.adapter);
    if (!adapter) {
      throw new CLIError(`Adapter '${options.adapter}' not found`, ErrorType.VALIDATION, 'CLI-102', [
        'Available adapters: vercel, netlify, aws-lambda',
        'Example: ordojs deploy --adapter vercel'
      ]);
    }

    // Load deployment configuration
    let deploymentConfig;
    if (options.config) {
      try {
        const configContent = await readFile(options.config);
        deploymentConfig = JSON.parse(configContent);
      } catch (error) {
        throw new CLIError(`Failed to load deployment configuration: ${error instanceof Error ? error.message : String(error)}`, ErrorType.VALIDATION, 'CLI-103', [
          'Check if the configuration file exists and contains valid JSON'
        ]);
      }
    } else {
      // Create default configuration
      deploymentConfig = {
        outputDir: options.dir,
        isStatic: options.static,
        includeServerFunctions: options.server,
        env: options.env
      };

      // Add domain configuration if provided
      if (options.domain) {
        deploymentConfig.domain = {
          name: options.domain,
          useHttps: true
        };
      }
    }

    // Validate deployment configuration
    const validation = adapter.validateConfig(deploymentConfig);
    if (!validation.valid) {
      throw new CLIError(`Invalid deployment configuration: ${validation.errors?.join(', ')}`, ErrorType.VALIDATION, 'CLI-104', [
        'Check your deployment configuration and try again'
      ]);
    }

    // Prepare deployment
    logger.info(`Preparing deployment with ${adapter.name}...`);
    const result = await adapter.prepareDeployment(deploymentConfig);

    if (!result.success) {
      throw new CLIError(`Deployment preparation failed: ${result.error}`, ErrorType.DEPLOYMENT, 'CLI-105');
    }

    // Log generated files
    logger.info('Generated deployment files:');
    for (const file of result.generatedFiles) {
      logger.info(`  - ${file.path}`);
    }

    // Display deployment instructions
    logger.info('\nDeployment Instructions:');
    logger.info(result.instructions);

    // Display deployment URL if available
    if (result.deploymentUrl) {
      logger.success(`\nDeployment URL: ${result.deploymentUrl}`);
    }

    logger.success('Deployment preparation completed successfully');
  } catch (error) {
    if (error instanceof CLIError) {
      throw error;
    } else {
      throw new CLIError(
        `Deployment failed: ${error instanceof Error ? error.message : String(error)}`,
        ErrorType.DEPLOYMENT,
        'CLI-106'
      );
    }
  }
}
