/**
 * @fileoverview OrdoJS CLI - Vercel deployment adapter
 * Adapter for deploying to Vercel
 */

import path from 'path';
import { AssetOptimizer, OptimizationResults } from '../../asset-optimizer.js';
import { mkdir, writeFile } from '../../fs.js';
import { logger } from '../../logger.js';
import { DeploymentAdapter, DeploymentConfig, DeploymentResult } from '../adapter-interface.js';

/**
 * Vercel-specific configuration
 */
export interface VercelConfig extends DeploymentConfig {
  /**
   * Vercel project settings
   */
  settings?: {
    /**
     * Vercel project name
     */
    projectName?: string;

    /**
     * Vercel framework preset
     */
    framework?: string;

    /**
     * Vercel region
     */
    region?: string;

    /**
     * Node.js version
     */
    nodeVersion?: string;

    /**
     * Whether to use Edge Functions
     */
    useEdgeFunctions?: boolean;

    /**
     * Whether to use Vercel Analytics
     */
    analytics?: boolean;

    /**
     * Whether to use Vercel Image Optimization
     */
    imageOptimization?: boolean;
  };
}

/**
 * Vercel deployment adapter
 */
export class VercelAdapter implements DeploymentAdapter {
  /**
   * Adapter name
   */
  name = 'vercel';

  /**
   * Adapter description
   */
  description = 'Deploy to Vercel';

  /**
   * Validate Vercel deployment configuration
   * @param config Deployment configuration
   * @returns Validation result
   */
  validateConfig(config: DeploymentConfig): { valid: boolean; errors?: string[] } {
    const errors: string[] = [];

    // Check required fields
    if (!config.outputDir) {
      errors.push('outputDir is required');
    }

    // Validate Vercel-specific settings
    const vercelConfig = config as VercelConfig;
    if (vercelConfig.settings) {
      // Validate project name if provided
      if (vercelConfig.settings.projectName && !/^[a-z0-9-]+$/.test(vercelConfig.settings.projectName)) {
        errors.push('Project name must contain only lowercase letters, numbers, and hyphens');
      }

      // Validate Node.js version if provided
      if (vercelConfig.settings.nodeVersion && !/^[0-9]+\.[0-9]+\.[0-9]+$|^[0-9]+$/.test(vercelConfig.settings.nodeVersion)) {
        errors.push('Invalid Node.js version format');
      }
    }

    return {
      valid: errors.length === 0,
      errors: errors.length > 0 ? errors : undefined
    };
  }

  /**
   * Prepare Vercel deployment
   * @param config Deployment configuration
   * @returns Deployment result
   */
  async prepareDeployment(config: DeploymentConfig): Promise<DeploymentResult> {
    const vercelConfig = config as VercelConfig;
    const generatedFiles: Array<{ path: string; content: string }> = [];

    try {
      // Create vercel.json configuration
      const vercelJsonContent = this.generateVercelConfig(vercelConfig);
      const vercelJsonPath = path.join(config.outputDir, 'vercel.json');

      await writeFile(vercelJsonPath, vercelJsonContent);
      generatedFiles.push({
        path: vercelJsonPath,
        content: vercelJsonContent
      });

      // Create build output directory if it doesn't exist
      await mkdir(config.outputDir, { recursive: true });

      // Generate .vercel directory with project.json
      const projectJsonContent = this.generateProjectConfig(vercelConfig);
      const projectJsonDir = path.join(config.outputDir, '.vercel');
      const projectJsonPath = path.join(projectJsonDir, 'project.json');

      await mkdir(projectJsonDir, { recursive: true });
      await writeFile(projectJsonPath, projectJsonContent);
      generatedFiles.push({
        path: projectJsonPath,
        content: projectJsonContent
      });

      // Generate server functions if needed
      if (config.includeServerFunctions) {
        await this.generateServerFunctions(config);
      }

      // Optimize assets for Vercel
      const optimizationResults = await this.optimizeForDeployment(config, config.outputDir);

      return {
        success: true,
        generatedFiles,
        instructions: this.getDeploymentInstructions(vercelConfig),
        optimizationResults
      };
    } catch (error) {
      logger.error(`Vercel deployment preparation failed: ${error instanceof Error ? error.message : String(error)}`);

      return {
        success: false,
        error: `Vercel deployment preparation failed: ${error instanceof Error ? error.message : String(error)}`,
        generatedFiles,
        instructions: 'An error occurred during Vercel deployment preparation. Please check the logs for details.'
      };
    }
  }

  /**
   * Generate Vercel configuration
   * @param config Vercel configuration
   * @returns Vercel configuration JSON
   */
  private generateVercelConfig(config: VercelConfig): string {
    const vercelConfig: any = {
      version: 2,
      buildCommand: 'ordojs build --production',
      outputDirectory: config.outputDir,
      framework: config.settings?.framework || 'ordojs',
      regions: config.settings?.region ? [config.settings.region] : ['iad1'],
      env: config.env || {}
    };

    // Add headers if provided
    if (config.headers && config.headers.length > 0) {
      vercelConfig.headers = config.headers;
    }

    // Add redirects if provided
    if (config.redirects && config.redirects.length > 0) {
      vercelConfig.redirects = config.redirects;
    }

    // Add routes for API functions if needed
    if (config.includeServerFunctions) {
      vercelConfig.routes = [
        {
          src: '/api/(.*)',
          dest: '/api/$1'
        }
      ];
    }

    return JSON.stringify(vercelConfig, null, 2);
  }

  /**
   * Generate Vercel project configuration
   * @param config Vercel configuration
   * @returns Project configuration JSON
   */
  private generateProjectConfig(config: VercelConfig): string {
    const projectConfig: any = {
      projectId: config.settings?.projectName || 'ordojs-app',
      orgId: 'your-org-id',
      settings: {
        framework: config.settings?.framework || 'ordojs',
        nodeVersion: config.settings?.nodeVersion || '18.x'
      }
    };

    return JSON.stringify(projectConfig, null, 2);
  }

  /**
   * Generate server functions for Vercel
   * @param config Deployment configuration
   */
  private async generateServerFunctions(config: DeploymentConfig): Promise<void> {
    // Create api directory
    const apiDir = path.join(config.outputDir, 'api');
    await mkdir(apiDir, { recursive: true });

    // Generate example API function
    const exampleFunctionContent = `
export default function handler(req, res) {
  res.status(200).json({
    message: 'Hello from OrdoJS on Vercel!',
    timestamp: new Date().toISOString()
  });
}
`;

    await writeFile(path.join(apiDir, 'hello.js'), exampleFunctionContent);
  }

  /**
   * Get deployment instructions
   * @param config Vercel configuration
   * @returns Deployment instructions
   */
  private getDeploymentInstructions(config: VercelConfig): string {
    return `
# Vercel Deployment Instructions

Your project has been prepared for deployment to Vercel.

## Prerequisites

1. Install the Vercel CLI:
   \`\`\`
   npm install -g vercel
   \`\`\`

2. Login to Vercel:
   \`\`\`
   vercel login
   \`\`\`

## Deployment

To deploy your application to Vercel, run:

\`\`\`
cd ${config.outputDir}
vercel --prod
\`\`\`

## Configuration

The following files have been generated:

- \`vercel.json\`: Vercel configuration file
- \`.vercel/project.json\`: Project configuration

You can customize these files to adjust your deployment settings.

## Environment Variables

${config.env && Object.keys(config.env).length > 0
  ? 'The following environment variables have been configured:\n\n' +
    Object.entries(config.env).map(([key, value]) => `- ${key}: ${value}`).join('\n')
  : 'No environment variables have been configured. You can add them in the Vercel dashboard or in the vercel.json file.'
}

## Custom Domain

${config.domain
  ? `Your application will be available at: ${config.domain.name}`
  : 'You can configure a custom domain in the Vercel dashboard after deployment.'
}
`;
  }

  /**
   * Optimize assets for Vercel deployment
   * @param config Deployment configuration
   * @param outputDir Output directory
   * @returns Optimization results
   */
  async optimizeForDeployment(config: DeploymentConfig, outputDir: string): Promise<OptimizationResults> {
    logger.info('Optimizing assets for Vercel deployment...');

    // Initialize asset optimizer with Vercel-specific options
    const optimizer = new AssetOptimizer({
      minifyJs: true,
      minifyCss: true,
      brotli: true,
      gzip: true,
      sizeReport: true,
      terserOptions: {
        compress: {
          passes: 2,
          drop_console: true,
          drop_debugger: true
        },
        mangle: true,
        format: {
          comments: false
        }
      }
    });

    // Optimize all assets in the output directory
    const optimizationResults = await optimizer.optimizeDirectory(outputDir);

    // Generate and save size report
    const sizeReport = optimizer.generateSizeReport(optimizationResults);
    await writeFile(path.join(outputDir, 'size-report.txt'), sizeReport);

    return optimizationResults;
  }

  /**
   * Get Vercel-specific environment variables
   * @param config Deployment configuration
   * @returns Environment variables
   */
  getEnvironmentVariables(config: DeploymentConfig): Record<string, string> {
    const env: Record<string, string> = {
      VERCEL: '1',
      NODE_ENV: 'production',
      ...config.env
    };

    // Add Vercel-specific environment variables
    if (config.domain) {
      env.VERCEL_URL = config.domain.name;
    }

    return env;
  }

  /**
   * Get Vercel deployment command
   * @param config Deployment configuration
   * @returns Deployment command
   */
  getDeployCommand(config: DeploymentConfig): string {
    return `cd ${config.outputDir} && vercel --prod`;
  }
}
