/**
 * @fileoverview OrdoJS CLI - CI/CD pipeline generator
 */

import { CLIError, ErrorType } from '../index.js';
import type { DeploymentConfig } from './adapter-interface.js';

export interface CICDConfig {
  platform: 'github' | 'gitlab' | 'jenkins';
  nodeVersion: string;
  pnpmVersion: string;
  testCommand: string;
  buildCommand: string;
  deployCommand: string;
  cacheDependencies: boolean;
  runTests: boolean;
  runLinting: boolean;
  runSecurityScan: boolean;
  autoDeploy: boolean;
  environments: string[];
  secrets: string[];
}

export interface PipelineOptions {
  platform?: 'github' | 'gitlab' | 'jenkins';
  nodeVersion?: string;
  pnpmVersion?: string;
  testCommand?: string;
  buildCommand?: string;
  deployCommand?: string;
  cacheDependencies?: boolean;
  runTests?: boolean;
  runLinting?: boolean;
  runSecurityScan?: boolean;
  autoDeploy?: boolean;
  environments?: string[];
  secrets?: string[];
}

/**
 * CI/CD pipeline generator for OrdoJS applications
 */
export class CICDGenerator {
  private defaultConfig: CICDConfig = {
    platform: 'github',
    nodeVersion: '18',
    pnpmVersion: '8',
    testCommand: 'pnpm test',
    buildCommand: 'pnpm build',
    deployCommand: 'pnpm deploy',
    cacheDependencies: true,
    runTests: true,
    runLinting: true,
    runSecurityScan: true,
    autoDeploy: false,
    environments: ['production', 'staging'],
    secrets: []
  };

  /**
   * Generate CI/CD pipeline configuration
   */
  generatePipeline(config: DeploymentConfig, options: PipelineOptions = {}): string {
    const cicdConfig = this.mergeConfig(options);

    try {
      switch (cicdConfig.platform) {
        case 'github':
          return this.generateGitHubActions(cicdConfig, config);
        case 'gitlab':
          return this.generateGitLabCI(cicdConfig, config);
        case 'jenkins':
          return this.generateJenkinsPipeline(cicdConfig, config);
        default:
          throw new Error(`Unsupported platform: ${cicdConfig.platform}`);
      }
    } catch (error) {
      throw new CLIError(
        `Failed to generate CI/CD pipeline: ${error instanceof Error ? error.message : String(error)}`,
        ErrorType.DEPLOYMENT,
        'CICD-001'
      );
    }
  }

  /**
   * Generate GitHub Actions workflow
   */
  generateGitHubActions(config: CICDConfig, deploymentConfig: DeploymentConfig): string {
    return `name: OrdoJS CI/CD Pipeline

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

env:
  NODE_VERSION: '${config.nodeVersion}'
  PNPM_VERSION: '${config.pnpmVersion}'

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: \${{ env.NODE_VERSION }}

    - name: Setup pnpm
      uses: pnpm/action-setup@v2
      with:
        version: \${{ env.PNPM_VERSION }}

    - name: Get pnpm store directory
      shell: bash
      run: |
        echo "STORE_PATH=\\\${{ pnpm store path }}" >> \$GITHUB_ENV

    - name: Setup pnpm cache
      uses: actions/cache@v3
      with:
        path: \${{ env.STORE_PATH }}
        key: \${{ runner.os }}-pnpm-store-\${{ hashFiles('**/pnpm-lock.yaml') }}
        restore-keys: |
          \${{ runner.os }}-pnpm-store-

    - name: Install dependencies
      run: pnpm install --frozen-lockfile

    ${config.runLinting ? this.generateLintingStep() : ''}
    ${config.runTests ? this.generateTestStep() : ''}
    ${config.runSecurityScan ? this.generateSecurityScanStep() : ''}

  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' || github.event_name == 'pull_request'
    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: \${{ env.NODE_VERSION }}

    - name: Setup pnpm
      uses: pnpm/action-setup@v2
      with:
        version: \${{ env.PNPM_VERSION }}

    - name: Get pnpm store directory
      shell: bash
      run: |
        echo "STORE_PATH=\\\${{ pnpm store path }}" >> \$GITHUB_ENV

    - name: Setup pnpm cache
      uses: actions/cache@v3
      with:
        path: \${{ env.STORE_PATH }}
        key: \${{ runner.os }}-pnpm-store-\${{ hashFiles('**/pnpm-lock.yaml') }}
        restore-keys: |
          \${{ runner.os }}-pnpm-store-

    - name: Install dependencies
      run: pnpm install --frozen-lockfile

    - name: Build application
      run: ${config.buildCommand}

    - name: Upload build artifacts
      uses: actions/upload-artifact@v3
      with:
        name: build-artifacts
        path: dist/

  ${config.autoDeploy ? this.generateDeployJob(config) : ''}
`;
  }

  /**
   * Generate GitLab CI configuration
   */
  generateGitLabCI(config: CICDConfig, deploymentConfig: DeploymentConfig): string {
    return `# GitLab CI/CD Pipeline for OrdoJS
image: node:${config.nodeVersion}-alpine

variables:
  PNPM_VERSION: "${config.pnpmVersion}"

cache:
  paths:
    - node_modules/
    - .pnpm-store/

stages:
  - test
  - build
  ${config.autoDeploy ? '- deploy' : ''}

before_script:
  - npm install -g pnpm@${config.pnpmVersion}
  - pnpm install --frozen-lockfile

test:
  stage: test
  script:
    ${config.runLinting ? `- pnpm lint` : ''}
    ${config.runTests ? `- ${config.testCommand}` : ''}
    ${config.runSecurityScan ? `- pnpm audit` : ''}
  artifacts:
    reports:
      junit: test-results.xml
    expire_in: 1 week

build:
  stage: build
  script:
    - ${config.buildCommand}
  artifacts:
    paths:
      - dist/
    expire_in: 1 week
  only:
    - main
    - develop

${config.autoDeploy ? this.generateGitLabDeployStage(config) : ''}
`;
  }

  /**
   * Generate Jenkins pipeline
   */
  generateJenkinsPipeline(config: CICDConfig, deploymentConfig: DeploymentConfig): string {
    return `pipeline {
    agent {
        docker {
            image 'node:${config.nodeVersion}-alpine'
            args '-u root'
        }
    }

    environment {
        PNPM_VERSION = '${config.pnpmVersion}'
        NODE_ENV = 'production'
    }

    stages {
        stage('Setup') {
            steps {
                sh 'npm install -g pnpm@${config.pnpmVersion}'
                sh 'pnpm install --frozen-lockfile'
            }
        }

        ${config.runLinting ? `
        stage('Lint') {
            steps {
                sh 'pnpm lint'
            }
        }` : ''}

        ${config.runTests ? `
        stage('Test') {
            steps {
                sh '${config.testCommand}'
            }
            post {
                always {
                    publishHTML([
                        allowMissing: false,
                        alwaysLinkToLastBuild: true,
                        keepAll: true,
                        reportDir: 'coverage',
                        reportFiles: 'index.html',
                        reportName: 'Coverage Report'
                    ])
                }
            }
        }` : ''}

        ${config.runSecurityScan ? `
        stage('Security Scan') {
            steps {
                sh 'pnpm audit'
            }
        }` : ''}

        stage('Build') {
            steps {
                sh '${config.buildCommand}'
            }
            post {
                success {
                    archiveArtifacts artifacts: 'dist/**/*', fingerprint: true
                }
            }
        }

        ${config.autoDeploy ? `
        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                sh '${config.deployCommand}'
            }
        }` : ''}
    }

    post {
        always {
            cleanWs()
        }
        success {
            echo 'Pipeline completed successfully!'
        }
        failure {
            echo 'Pipeline failed!'
        }
    }
}`;
  }

  /**
   * Generate deployment job for GitHub Actions
   */
  private generateDeployJob(config: CICDConfig): string {
    return `
  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment: production
    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Download build artifacts
      uses: actions/download-artifact@v3
      with:
        name: build-artifacts
        path: dist/

    - name: Deploy to production
      run: ${config.deployCommand}
      env:
        ${config.secrets.map(secret => `${secret}: \${{ secrets.${secret} }}`).join('\n        ')}
`;
  }

  /**
   * Generate GitLab deploy stage
   */
  private generateGitLabDeployStage(config: CICDConfig): string {
    return `
deploy:
  stage: deploy
  script:
    - ${config.deployCommand}
  environment:
    name: production
  only:
    - main
  when: manual
`;
  }

  /**
   * Generate linting step for GitHub Actions
   */
  private generateLintingStep(): string {
    return `
    - name: Run linting
      run: pnpm lint`;
  }

  /**
   * Generate test step for GitHub Actions
   */
  private generateTestStep(): string {
    return `
    - name: Run tests
      run: ${this.defaultConfig.testCommand}
      env:
        CI: true`;
  }

  /**
   * Generate security scan step for GitHub Actions
   */
  private generateSecurityScanStep(): string {
    return `
    - name: Security scan
      run: pnpm audit`;
  }

  private mergeConfig(options: PipelineOptions): CICDConfig {
    return {
      ...this.defaultConfig,
      ...options,
      environments: [...this.defaultConfig.environments, ...(options.environments || [])],
      secrets: [...this.defaultConfig.secrets, ...(options.secrets || [])]
    };
  }
}
