/**
 * @fileoverview Tests for the CI/CD generator
 */

import { beforeEach, describe, expect, it } from 'vitest';
import type { DeploymentConfig } from './adapter-interface.js';
import { CICDGenerator } from './cicd-generator.js';

describe('CICDGenerator', () => {
  let cicdGenerator: CICDGenerator;
  let mockDeploymentConfig: DeploymentConfig;

  beforeEach(() => {
    cicdGenerator = new CICDGenerator();
    mockDeploymentConfig = {
      outputDir: 'dist',
      isStatic: false,
      includeServerFunctions: true,
      env: {
        NODE_ENV: 'production',
        PORT: '3000'
      }
    };
  });

  describe('generatePipeline', () => {
    it('should generate GitHub Actions pipeline by default', () => {
      const pipeline = cicdGenerator.generatePipeline(mockDeploymentConfig);

      expect(pipeline).toContain('name: OrdoJS CI/CD Pipeline');
      expect(pipeline).toContain('on:');
      expect(pipeline).toContain('push:');
      expect(pipeline).toContain('pull_request:');
      expect(pipeline).toContain('jobs:');
      expect(pipeline).toContain('test:');
      expect(pipeline).toContain('build:');
    });

    it('should generate GitLab CI pipeline', () => {
      const pipeline = cicdGenerator.generatePipeline(mockDeploymentConfig, {
        platform: 'gitlab'
      });

      expect(pipeline).toContain('# GitLab CI/CD Pipeline for OrdoJS');
      expect(pipeline).toContain('image: node:18-alpine');
      expect(pipeline).toContain('stages:');
      expect(pipeline).toContain('- test');
      expect(pipeline).toContain('- build');
    });

    it('should generate Jenkins pipeline', () => {
      const pipeline = cicdGenerator.generatePipeline(mockDeploymentConfig, {
        platform: 'jenkins'
      });

      expect(pipeline).toContain('pipeline {');
      expect(pipeline).toContain('agent {');
      expect(pipeline).toContain('stages {');
      expect(pipeline).toContain('stage(\'Setup\')');
      expect(pipeline).toContain('stage(\'Build\')');
    });

    it('should throw error for unsupported platform', () => {
      expect(() => {
        cicdGenerator.generatePipeline(mockDeploymentConfig, {
          platform: 'unsupported' as any
        });
      }).toThrow('Unsupported platform: unsupported');
    });
  });

  describe('generateGitHubActions', () => {
    it('should generate complete GitHub Actions workflow', () => {
      const config = {
        platform: 'github' as const,
        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: []
      };

      const workflow = cicdGenerator.generateGitHubActions(config, mockDeploymentConfig);

      expect(workflow).toContain('name: OrdoJS CI/CD Pipeline');
      expect(workflow).toContain('on:');
      expect(workflow).toContain('push:');
      expect(workflow).toContain('branches: [ main, develop ]');
      expect(workflow).toContain('pull_request:');
      expect(workflow).toContain('branches: [ main ]');
      expect(workflow).toContain('env:');
      expect(workflow).toContain('NODE_VERSION: \'18\'');
      expect(workflow).toContain('PNPM_VERSION: \'8\'');
      expect(workflow).toContain('jobs:');
      expect(workflow).toContain('test:');
      expect(workflow).toContain('build:');
      expect(workflow).toContain('runs-on: ubuntu-latest');
      expect(workflow).toContain('uses: actions/checkout@v4');
      expect(workflow).toContain('uses: actions/setup-node@v4');
      expect(workflow).toContain('uses: pnpm/action-setup@v2');
      expect(workflow).toContain('run: pnpm install --frozen-lockfile');
    });

    it('should include linting step when enabled', () => {
      const config = {
        ...cicdGenerator['defaultConfig'],
        runLinting: true
      };

      const workflow = cicdGenerator.generateGitHubActions(config, mockDeploymentConfig);

      expect(workflow).toContain('Run linting');
      expect(workflow).toContain('run: pnpm lint');
    });

    it('should include test step when enabled', () => {
      const config = {
        ...cicdGenerator['defaultConfig'],
        runTests: true
      };

      const workflow = cicdGenerator.generateGitHubActions(config, mockDeploymentConfig);

      expect(workflow).toContain('Run tests');
      expect(workflow).toContain('run: pnpm test');
      expect(workflow).toContain('CI: true');
    });

    it('should include security scan step when enabled', () => {
      const config = {
        ...cicdGenerator['defaultConfig'],
        runSecurityScan: true
      };

      const workflow = cicdGenerator.generateGitHubActions(config, mockDeploymentConfig);

      expect(workflow).toContain('Security scan');
      expect(workflow).toContain('run: pnpm audit');
    });

    it('should include deployment job when autoDeploy is enabled', () => {
      const config = {
        ...cicdGenerator['defaultConfig'],
        autoDeploy: true,
        secrets: ['DEPLOY_TOKEN', 'API_KEY']
      };

      const workflow = cicdGenerator.generateGitHubActions(config, mockDeploymentConfig);

      expect(workflow).toContain('deploy:');
      expect(workflow).toContain('needs: build');
      expect(workflow).toContain('environment: production');
      expect(workflow).toContain('DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}');
      expect(workflow).toContain('API_KEY: ${{ secrets.API_KEY }}');
    });
  });

  describe('generateGitLabCI', () => {
    it('should generate complete GitLab CI configuration', () => {
      const config = {
        platform: 'gitlab' as const,
        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: []
      };

      const gitlabCI = cicdGenerator.generateGitLabCI(config, mockDeploymentConfig);

      expect(gitlabCI).toContain('# GitLab CI/CD Pipeline for OrdoJS');
      expect(gitlabCI).toContain('image: node:18-alpine');
      expect(gitlabCI).toContain('variables:');
      expect(gitlabCI).toContain('PNPM_VERSION: "8"');
      expect(gitlabCI).toContain('cache:');
      expect(gitlabCI).toContain('paths:');
      expect(gitlabCI).toContain('- node_modules/');
      expect(gitlabCI).toContain('- .pnpm-store/');
      expect(gitlabCI).toContain('stages:');
      expect(gitlabCI).toContain('- test');
      expect(gitlabCI).toContain('- build');
      expect(gitlabCI).toContain('before_script:');
      expect(gitlabCI).toContain('npm install -g pnpm@8');
      expect(gitlabCI).toContain('pnpm install --frozen-lockfile');
    });

    it('should include linting in test stage', () => {
      const config = {
        ...cicdGenerator['defaultConfig'],
        runLinting: true
      };

      const gitlabCI = cicdGenerator.generateGitLabCI(config, mockDeploymentConfig);

      expect(gitlabCI).toContain('test:');
      expect(gitlabCI).toContain('stage: test');
      expect(gitlabCI).toContain('- pnpm lint');
    });

    it('should include deployment stage when autoDeploy is enabled', () => {
      const config = {
        ...cicdGenerator['defaultConfig'],
        autoDeploy: true
      };

      const gitlabCI = cicdGenerator.generateGitLabCI(config, mockDeploymentConfig);

      expect(gitlabCI).toContain('- deploy');
      expect(gitlabCI).toContain('deploy:');
      expect(gitlabCI).toContain('stage: deploy');
      expect(gitlabCI).toContain('environment:');
      expect(gitlabCI).toContain('name: production');
      expect(gitlabCI).toContain('when: manual');
    });
  });

  describe('generateJenkinsPipeline', () => {
    it('should generate complete Jenkins pipeline', () => {
      const config = {
        platform: 'jenkins' as const,
        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: []
      };

      const jenkinsfile = cicdGenerator.generateJenkinsPipeline(config, mockDeploymentConfig);

      expect(jenkinsfile).toContain('pipeline {');
      expect(jenkinsfile).toContain('agent {');
      expect(jenkinsfile).toContain('docker {');
      expect(jenkinsfile).toContain('image \'node:18-alpine\'');
      expect(jenkinsfile).toContain('environment {');
      expect(jenkinsfile).toContain('PNPM_VERSION = \'8\'');
      expect(jenkinsfile).toContain('NODE_ENV = \'production\'');
      expect(jenkinsfile).toContain('stages {');
      expect(jenkinsfile).toContain('stage(\'Setup\')');
      expect(jenkinsfile).toContain('stage(\'Build\')');
      expect(jenkinsfile).toContain('sh \'npm install -g pnpm@8\'');
      expect(jenkinsfile).toContain('sh \'pnpm install --frozen-lockfile\'');
    });

    it('should include linting stage when enabled', () => {
      const config = {
        ...cicdGenerator['defaultConfig'],
        runLinting: true
      };

      const jenkinsfile = cicdGenerator.generateJenkinsPipeline(config, mockDeploymentConfig);

      expect(jenkinsfile).toContain('stage(\'Lint\')');
      expect(jenkinsfile).toContain('sh \'pnpm lint\'');
    });

    it('should include test stage when enabled', () => {
      const config = {
        ...cicdGenerator['defaultConfig'],
        runTests: true
      };

      const jenkinsfile = cicdGenerator.generateJenkinsPipeline(config, mockDeploymentConfig);

      expect(jenkinsfile).toContain('stage(\'Test\')');
      expect(jenkinsfile).toContain('sh \'pnpm test\'');
      expect(jenkinsfile).toContain('publishHTML');
    });

    it('should include security scan stage when enabled', () => {
      const config = {
        ...cicdGenerator['defaultConfig'],
        runSecurityScan: true
      };

      const jenkinsfile = cicdGenerator.generateJenkinsPipeline(config, mockDeploymentConfig);

      expect(jenkinsfile).toContain('stage(\'Security Scan\')');
      expect(jenkinsfile).toContain('sh \'pnpm audit\'');
    });

    it('should include deployment stage when autoDeploy is enabled', () => {
      const config = {
        ...cicdGenerator['defaultConfig'],
        autoDeploy: true
      };

      const jenkinsfile = cicdGenerator.generateJenkinsPipeline(config, mockDeploymentConfig);

      expect(jenkinsfile).toContain('stage(\'Deploy\')');
      expect(jenkinsfile).toContain('when {');
      expect(jenkinsfile).toContain('branch \'main\'');
      expect(jenkinsfile).toContain('sh \'pnpm deploy\'');
    });
  });

  describe('error handling', () => {
    it('should throw CLIError when pipeline generation fails', () => {
      // Mock a scenario that would cause generation to fail
      const invalidConfig = {
        ...mockDeploymentConfig,
        outputDir: null as any
      };

      expect(() => {
        cicdGenerator.generatePipeline(invalidConfig);
      }).toThrow();
    });
  });
});
