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

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';

/**
 * Netlify-specific configuration
 */
export interface NetlifyConfig extends DeploymentConfig {
  /**
   * Netlify project settings
   */
  settings?: {
    /**
     * Netlify site name
     */
    siteName?: string;

    /**
     * Netlify team name
     */
    teamName?: string;

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

    /**
     * Whether to use Netlify Forms
     */
    useForms?: boolean;

    /**
     * Whether to use Netlify Identity
     */
    useIdentity?: boolean;

    /**
     * Whether to use Netlify Large Media
     */
    useLargeMedia?: boolean;

    /**
     * Whether to use Netlify Analytics
     */
    useAnalytics?: boolean;

    /**
     * Whether to use Netlify Split Testing
     */
    useSplitTesting?: boolean;
  };
}

/**
 * Netlify deployment adapter
 */
export class NetlifyAdapter implements DeploymentAdapter {
  /**
   * Adapter name
   */
  name = 'netlify';

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

  /**
   * Validate Netlify 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 Netlify-specific settings
    const netlifyConfig = config as NetlifyConfig;
    if (netlifyConfig.settings) {
      // Validate site name if provided
      if (netlifyConfig.settings.siteName && !/^[a-z0-9-]+$/.test(netlifyConfig.settings.siteName)) {
        errors.push('Site name must contain only lowercase letters, numbers, and hyphens');
      }
    }

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

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

    try {
      // Create netlify.toml configuration
      const netlifyTomlContent = this.generateNetlifyConfig(netlifyConfig);
      const netlifyTomlPath = path.join(config.outputDir, 'netlify.toml');

      await writeFile(netlifyTomlPath, netlifyTomlContent);
      generatedFiles.push({
        path: netlifyTomlPath,
        content: netlifyTomlContent
      });

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

      // Generate _redirects file
      if (config.redirects && config.redirects.length > 0) {
        const redirectsContent = this.generateRedirectsFile(config.redirects);
        const redirectsPath = path.join(config.outputDir, '_redirects');

        await writeFile(redirectsPath, redirectsContent);
        generatedFiles.push({
          path: redirectsPath,
          content: redirectsContent
        });
      }

      // Generate _headers file
      if (config.headers && config.headers.length > 0) {
        const headersContent = this.generateHeadersFile(config.headers);
        const headersPath = path.join(config.outputDir, '_headers');

        await writeFile(headersPath, headersContent);
        generatedFiles.push({
          path: headersPath,
          content: headersContent
        });
      }

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

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

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

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

  /**
   * Generate Netlify configuration
   * @param config Netlify configuration
   * @returns Netlify configuration TOML
   */
  private generateNetlifyConfig(config: NetlifyConfig): string {
    const siteName = config.settings?.siteName || 'ordojs-app';
    const publishDir = config.outputDir || 'dist';
    const functionsDir = config.includeServerFunctions ? 'functions' : undefined;

    let toml = `# Netlify configuration for OrdoJS
[build]
  publish = "${publishDir}"
  command = "ordojs build --production"
${functionsDir ? `  functions = "${functionsDir}"` : ''}

[dev]
  framework = "ordojs"
  command = "ordojs dev"
  port = 8888
  targetPort = 3000
  publish = "${publishDir}"
${functionsDir ? `  functions = "${functionsDir}"` : ''}

`;

    // Add environment variables
    if (config.env && Object.keys(config.env).length > 0) {
      toml += '[build.environment]\n';

      for (const [key, value] of Object.entries(config.env)) {
        toml += `  ${key} = "${value}"\n`;
      }

      toml += '\n';
    }

    // Add headers
    if (config.headers && config.headers.length > 0) {
      for (const header of config.headers) {
        toml += `[[headers]]\n`;
        toml += `  for = "${header.source}"\n`;
        toml += `  [headers.values]\n`;

        for (const h of header.headers) {
          toml += `    ${h.key} = "${h.value}"\n`;
        }

        toml += '\n';
      }
    }

    // Add redirects
    if (config.redirects && config.redirects.length > 0) {
      for (const redirect of config.redirects) {
        toml += `[[redirects]]\n`;
        toml += `  from = "${redirect.source}"\n`;
        toml += `  to = "${redirect.destination}"\n`;
        toml += `  status = ${redirect.permanent ? 301 : 302}\n`;
        toml += `  force = true\n\n`;
      }
    }

    // Add plugins
    toml += `[plugins]\n`;

    if (config.settings?.useAnalytics) {
      toml += `  package = "@netlify/plugin-analytics"\n\n`;
    }

    // Add site settings
    toml += `[build.processing]\n`;
    toml += `  skip_processing = false\n`;
    toml += `[build.processing.css]\n`;
    toml += `  bundle = true\n`;
    toml += `  minify = true\n`;
    toml += `[build.processing.js]\n`;
    toml += `  bundle = true\n`;
    toml += `  minify = true\n`;
    toml += `[build.processing.html]\n`;
    toml += `  pretty_urls = true\n`;
    toml += `[build.processing.images]\n`;
    toml += `  compress = true\n`;

    return toml;
  }

  /**
   * Generate Netlify _redirects file
   * @param redirects Redirects configuration
   * @returns Redirects file content
   */
  private generateRedirectsFile(redirects: Array<{ source: string; destination: string; permanent: boolean }>): string {
    return redirects.map(redirect => {
      return `${redirect.source} ${redirect.destination} ${redirect.permanent ? 301 : 302}`;
    }).join('\n');
  }

  /**
   * Generate Netlify _headers file
   * @param headers Headers configuration
   * @returns Headers file content
   */
  private generateHeadersFile(headers: Array<{ source: string; headers: Array<{ key: string; value: string }> }>): string {
    let content = '';

    for (const header of headers) {
      content += `${header.source}\n`;

      for (const h of header.headers) {
        content += `  ${h.key}: ${h.value}\n`;
      }

      content += '\n';
    }

    return content;
  }

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

    // Generate example function
    const exampleFunctionContent = `
exports.handler = async function(event, context) {
  return {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Hello from OrdoJS on Netlify!',
      timestamp: new Date().toISOString()
    })
  };
};
`;

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

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

Your project has been prepared for deployment to Netlify.

## Prerequisites

1. Install the Netlify CLI:
   \`\`\`
   npm install -g netlify-cli
   \`\`\`

2. Login to Netlify:
   \`\`\`
   netlify login
   \`\`\`

## Deployment

To deploy your application to Netlify, run:

\`\`\`
cd ${config.outputDir}
netlify deploy --prod
\`\`\`

## Configuration

The following files have been generated:

- \`netlify.toml\`: Netlify configuration file
${config.redirects && config.redirects.length > 0 ? '- `_redirects`: URL redirects configuration\n' : ''}
${config.headers && config.headers.length > 0 ? '- `_headers`: HTTP headers configuration\n' : ''}
${config.includeServerFunctions ? '- `functions/`: Netlify Functions directory\n' : ''}

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 Netlify dashboard or in the netlify.toml file.'
}

## Custom Domain

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

  /**
   * Optimize assets for Netlify 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 Netlify deployment...');

    // Initialize asset optimizer with Netlify-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 Netlify-specific environment variables
   * @param config Deployment configuration
   * @returns Environment variables
   */
  getEnvironmentVariables(config: DeploymentConfig): Record<string, string> {
    const env: Record<string, string> = {
      NETLIFY: 'true',
      CONTEXT: 'production',
      NODE_ENV: 'production',
      ...config.env
    };

    // Add Netlify-specific environment variables
    if (config.domain) {
      env.URL = `https://${config.domain.name}`;
    }

    return env;
  }

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