/**
 * CI/CD Integration for AI Debug Local MCP
 * Generates automated CI/CD templates for competitive parity
 * GitHub Issue #1: CI/CD Integration - Competitive Parity Feature
 */

import fs from 'fs/promises';
import path from 'path';

interface CICDOptions {
  provider?: string;
  appUrl?: string;
  framework?: string;
  testCommand?: string;
  setupCommand?: string;
  environment?: Record<string, any>;
  hasTidewave?: boolean;
  tools?: string[];
}

interface CICDConfig extends CICDOptions {
  appUrl: string;
  framework: string;
  provider: string;
}

class CICDIntegration {
  private supportedFrameworks: string[];
  private supportedProviders: string[];
  
  constructor() {
    this.supportedFrameworks = ['react', 'vue', 'angular', 'nextjs', 'phoenix', 'rails', 'node'];
    this.supportedProviders = ['github', 'gitlab', 'circleci', 'jenkins'];
  }

  /**
   * Initialize CI/CD setup for a project
   */
  async initCI(projectDir: string, options: CICDOptions = {}) {
    const {
      provider = 'github',
      appUrl = 'http://localhost:3000',
      framework
    } = options;

    try {
      // Validate inputs
      this.validateConfig({ appUrl, provider, framework });

      // Detect framework if not provided
      const detectedFramework = framework || await this.detectFramework(projectDir);
      
      const config: CICDConfig = {
        appUrl,
        framework: detectedFramework,
        provider,
        ...options
      };

      const generatedFiles: string[] = [];

      // Generate CI/CD templates based on provider
      switch (provider) {
        case 'github':
          const githubFile = await this.generateGitHubActions(projectDir, config);
          generatedFiles.push(githubFile);
          break;
        case 'gitlab':
          const gitlabFile = await this.generateGitLabCI(projectDir, config);
          generatedFiles.push(gitlabFile);
          break;
        default:
          throw new Error(`Unsupported CI/CD provider: ${provider}`);
      }

      // Add NPM scripts
      await this.addNPMScripts(projectDir, config);
      generatedFiles.push('package.json');

      return {
        success: true,
        files: generatedFiles.map((f: string) => path.relative(projectDir, f)),
        framework: detectedFramework,
        config
      };

    } catch (error) {
      throw new Error(`CI/CD initialization failed: ${error instanceof Error ? error.message : String(error)}`);
    }
  }

  /**
   * Generate GitHub Actions workflow
   */
  async generateGitHubActions(projectDir: string, config: CICDConfig) {
    await this.ensureDirectoryExists(projectDir);
    
    const workflowDir = path.join(projectDir, '.github', 'workflows');
    await fs.mkdir(workflowDir, { recursive: true });
    
    const workflowPath = path.join(workflowDir, 'ai-debug.yml');
    const template = this.generateGitHubActionsTemplate(config);
    
    await fs.writeFile(workflowPath, template, 'utf8');
    return workflowPath;
  }

  /**
   * Generate GitLab CI configuration
   */
  async generateGitLabCI(projectDir: string, config: CICDConfig) {
    await this.ensureDirectoryExists(projectDir);
    
    const configPath = path.join(projectDir, '.gitlab-ci.yml');
    const template = this.generateGitLabCITemplate(config);
    
    await fs.writeFile(configPath, template, 'utf8');
    return configPath;
  }

  /**
   * Add NPM scripts for AI debugging
   */
  async addNPMScripts(projectDir: string, config: CICDConfig) {
    const packageJsonPath = path.join(projectDir, 'package.json');
    
    let packageJson: any;
    try {
      const content = await fs.readFile(packageJsonPath, 'utf8');
      packageJson = JSON.parse(content);
    } catch (error) {
      // Create basic package.json if it doesn't exist
      packageJson = {
        name: path.basename(projectDir),
        version: '1.0.0',
        scripts: {}
      };
    }

    // Add AI debug scripts
    packageJson.scripts = {
      ...packageJson.scripts,
      'ai-debug': 'ai-debug-mcp debug_page --url=' + config.appUrl,
      'ai-debug:ci': `ai-debug-mcp debug_page --url=${config.appUrl} --audit --ci`,
      'ai-debug:performance': `ai-debug-mcp performance_audit --url=${config.appUrl}`,
      'ai-debug:accessibility': `ai-debug-mcp run_accessibility_check --url=${config.appUrl}`
    };

    // Add Tidewave scripts for Phoenix/Rails
    if (config.framework === 'phoenix' || config.framework === 'rails') {
      packageJson.scripts['ai-debug:tidewave'] = `ai-debug-mcp tidewave_query --url=${config.appUrl} --tool=logs`;
    }

    await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8');
    return packageJsonPath;
  }

  /**
   * Detect project framework
   */
  async detectFramework(projectDir: string): Promise<string> {
    try {
      // Check for Phoenix (mix.exs)
      const mixPath = path.join(projectDir, 'mix.exs');
      try {
        await fs.access(mixPath);
        return 'phoenix';
      } catch {}

      // Check for Rails (Gemfile)
      const gemfilePath = path.join(projectDir, 'Gemfile');
      try {
        const gemfileContent = await fs.readFile(gemfilePath, 'utf8');
        if (gemfileContent.includes('rails')) {
          return 'rails';
        }
      } catch {}

      // Check for Node.js projects (package.json)
      const packageJsonPath = path.join(projectDir, 'package.json');
      try {
        const packageContent = await fs.readFile(packageJsonPath, 'utf8');
        const packageJson = JSON.parse(packageContent);
        const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };

        if (deps.react) return 'react';
        if (deps.vue) return 'vue';
        if (deps['@angular/core']) return 'angular';
        if (deps.next) return 'nextjs';
        return 'node';
      } catch {}

      return 'unknown';
    } catch (error) {
      return 'unknown';
    }
  }

  /**
   * Generate GitHub Actions template
   */
  generateGitHubActionsTemplate(config: CICDConfig) {
    const {
      appUrl = 'http://localhost:3000',
      framework = 'node',
      testCommand = 'npm test',
      setupCommand = 'npm install',
      environment = {},
      hasTidewave = false,
      tools = ['debug_page', 'performance_audit']
    } = config;

    const envVars = Object.entries(environment)
      .map(([key, value]: [string, any]) => `        ${key}: ${value}`)
      .join('\n');

    const frameworkSetup = this.getFrameworkSetup(framework);
    const tidewaveConfig = hasTidewave ? this.getTidewaveConfig(framework) : '';

    return `name: AI Debug Tests

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

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

    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '18'
        cache: 'npm'

${frameworkSetup}

    - name: Install dependencies
      run: ${setupCommand}

    - name: Install AI Debug MCP
      run: npm install -g @living-software/ai-debug-local-mcp@latest

    - name: Start application
      run: |
        ${this.getStartCommand(framework)} &
        sleep 10  # Wait for app to start
      env:
${envVars || '        NODE_ENV: test'}

    - name: Run AI Debug Tests
      run: |
        ${tools.map((tool: string) => `ai-debug-mcp ${tool} --url=${appUrl}`).join('\n        ')}
      env:
        APP_URL: ${appUrl}
${tidewaveConfig}

    - name: Upload Debug Reports
      uses: actions/upload-artifact@v4
      if: always()
      with:
        name: ai-debug-reports
        path: debug-reports/
        retention-days: 30
`;
  }

  /**
   * Generate GitLab CI template
   */
  generateGitLabCITemplate(config: CICDConfig) {
    const {
      appUrl = 'http://localhost:3000',
      framework = 'node',
      environment = {}
    } = config;

    const envVars = Object.entries(environment)
      .map(([key, value]: [string, any]) => `  ${key}: "${value}"`)
      .join('\n');

    return `stages:
  - test

variables:
  APP_URL: ${appUrl}
${envVars}

ai-debug-tests:
  stage: test
  image: node:18
  before_script:
    - npm install -g @living-software/ai-debug-local-mcp@latest
    - npm install
  script:
    - ${this.getStartCommand(framework)} &
    - sleep 10
    - ai-debug-mcp debug_page --url=$APP_URL
    - ai-debug-mcp performance_audit --url=$APP_URL
    - ai-debug-mcp run_accessibility_check --url=$APP_URL
  artifacts:
    reports:
      junit: debug-reports/junit.xml
    paths:
      - debug-reports/
    expire_in: 1 week
  only:
    - main
    - develop
    - merge_requests
`;
  }

  /**
   * Generate workflow template (for testing)
   */
  generateWorkflowTemplate(config: CICDConfig) {
    return this.generateGitHubActionsTemplate(config);
  }

  /**
   * Get framework-specific setup steps
   */
  getFrameworkSetup(framework: string) {
    switch (framework) {
      case 'phoenix':
        return `    - name: Setup Elixir
      uses: erlef/setup-beam@v1
      with:
        elixir-version: '1.15'
        otp-version: '26'

    - name: Install Elixir dependencies
      run: mix deps.get`;

      case 'rails':
        return `    - name: Setup Ruby
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: '3.1'
        bundler-cache: true`;

      default:
        return '';
    }
  }

  /**
   * Get framework-specific start command
   */
  getStartCommand(framework: string) {
    switch (framework) {
      case 'phoenix':
        return 'mix phx.server';
      case 'rails':
        return 'rails server';
      case 'nextjs':
        return 'npm run dev';
      case 'react':
        return 'npm start';
      default:
        return 'npm start';
    }
  }

  /**
   * Get Tidewave configuration for Phoenix/Rails
   */
  getTidewaveConfig(framework: string) {
    if (framework === 'phoenix' || framework === 'rails') {
      return `        TIDEWAVE_ENABLED: true
        TIDEWAVE_TOOLS: "logs,sql,processes"`;
    }
    return '';
  }

  /**
   * Validate configuration
   */
  validateConfig(config: Partial<CICDConfig>) {
    const { appUrl, provider, framework } = config;

    // Validate URL
    if (appUrl && !this.isValidUrl(appUrl)) {
      throw new Error('Invalid configuration: appUrl must be a valid URL');
    }

    // Validate provider
    if (provider && !this.supportedProviders.includes(provider)) {
      throw new Error(`Invalid configuration: unsupported provider ${provider}`);
    }

    // Validate framework
    if (framework && !this.supportedFrameworks.includes(framework)) {
      throw new Error(`Invalid configuration: unsupported framework ${framework}`);
    }
  }

  /**
   * Check if URL is valid
   */
  isValidUrl(string: string) {
    try {
      new URL(string);
      return true;
    } catch {
      return false;
    }
  }

  /**
   * Ensure directory exists
   */
  async ensureDirectoryExists(dir: string) {
    try {
      await fs.access(dir);
    } catch {
      throw new Error('Directory does not exist: ' + dir);
    }
  }
}

export { CICDIntegration };