#!/usr/bin/env node

import { writeFileSync } from 'fs';
import { join } from 'path';
import { SecurityAuditor, type SecurityAuditOptions } from './security-auditor';
import { VulnerabilityScanner } from './vulnerability-scanner';

interface CLIOptions {
  projectPath: string;
  output?: string;
  format?: 'json' | 'html' | 'markdown' | 'csv';
  severity?: 'low' | 'medium' | 'high' | 'critical';
  includePatterns?: string[];
  excludePatterns?: string[];
  enableDependencyCheck?: boolean;
  enableCodeAnalysis?: boolean;
  enableConfigurationCheck?: boolean;
  generateReport?: boolean;
  generateFixScript?: boolean;
  verbose?: boolean;
}

class SecurityAuditCLI {
  private options: CLIOptions;

  constructor(options: CLIOptions) {
    this.options = {
      format: 'json',
      severity: 'low',
      enableDependencyCheck: true,
      enableCodeAnalysis: true,
      enableConfigurationCheck: true,
      generateReport: true,
      verbose: false,
      ...options,
    };
  }

  async run(): Promise<void> {
    try {
      if (this.options.verbose) {
        console.log('🔍 Starting OrdoJS Security Audit...');
        console.log(`📁 Project path: ${this.options.projectPath}`);
      }

      // Run security audit
      const auditorOptions: SecurityAuditOptions = {
        projectPath: this.options.projectPath,
      };

      if (this.options.includePatterns) {
        auditorOptions.includePatterns = this.options.includePatterns;
      }
      if (this.options.excludePatterns) {
        auditorOptions.excludePatterns = this.options.excludePatterns;
      }
      if (this.options.enableDependencyCheck !== undefined) {
        auditorOptions.enableDependencyCheck = this.options.enableDependencyCheck;
      }
      if (this.options.enableCodeAnalysis !== undefined) {
        auditorOptions.enableCodeAnalysis = this.options.enableCodeAnalysis;
      }
      if (this.options.enableConfigurationCheck !== undefined) {
        auditorOptions.enableConfigurationCheck = this.options.enableConfigurationCheck;
      }

      const auditor = new SecurityAuditor(auditorOptions);

      const auditResult = await auditor.audit();

      // Filter by severity if specified
      if (this.options.severity && this.options.severity !== 'low') {
        const severityLevels = ['low', 'medium', 'high', 'critical'];
        const minSeverityIndex = severityLevels.indexOf(this.options.severity);

        auditResult.vulnerabilities = auditResult.vulnerabilities.filter(vuln => {
          const vulnSeverityIndex = severityLevels.indexOf(vuln.severity);
          return vulnSeverityIndex >= minSeverityIndex;
        });

        // Recalculate summary
        auditResult.summary = auditResult.vulnerabilities.reduce(
          (acc, vuln) => {
            acc.total++;
            acc[vuln.severity]++;
            return acc;
          },
          { total: 0, critical: 0, high: 0, medium: 0, low: 0 }
        );
      }

      // Generate dependency vulnerability report
      let dependencyReport;
      if (this.options.enableDependencyCheck) {
        const scanner = new VulnerabilityScanner({
          projectPath: this.options.projectPath,
        });
        dependencyReport = await scanner.scanDependencies();
      }

      // Display results
      this.displayResults(auditResult, dependencyReport);

      // Generate output files
      if (this.options.output || this.options.generateReport) {
        await this.generateOutputFiles(auditResult, dependencyReport);
      }

      // Generate fix script
      if (this.options.generateFixScript && dependencyReport) {
        await this.generateFixScript(dependencyReport);
      }

      // Exit with appropriate code
      const hasHighSeverityIssues = auditResult.summary.critical > 0 || auditResult.summary.high > 0;
      process.exit(hasHighSeverityIssues ? 1 : 0);

    } catch (error) {
      console.error('❌ Security audit failed:', error);
      process.exit(1);
    }
  }

  private displayResults(auditResult: any, dependencyReport?: any): void {
    console.log('\n📊 Security Audit Results');
    console.log('=' .repeat(50));

    // Summary
    console.log(`\n📈 Summary:`);
    console.log(`   Total vulnerabilities: ${auditResult.summary.total}`);
    console.log(`   🔴 Critical: ${auditResult.summary.critical}`);
    console.log(`   🟠 High: ${auditResult.summary.high}`);
    console.log(`   🟡 Medium: ${auditResult.summary.medium}`);
    console.log(`   🟢 Low: ${auditResult.summary.low}`);

    // OWASP Compliance
    console.log(`\n🛡️  OWASP Compliance Score: ${auditResult.owaspCompliance.score}%`);

    // Dependency vulnerabilities
    if (dependencyReport) {
      console.log(`\n📦 Dependency Vulnerabilities: ${dependencyReport.summary.total}`);
      console.log(`   🔴 Critical: ${dependencyReport.summary.critical}`);
      console.log(`   🟠 High: ${dependencyReport.summary.high}`);
      console.log(`   🟡 Medium: ${dependencyReport.summary.medium}`);
      console.log(`   🟢 Low: ${dependencyReport.summary.low}`);
    }

    // Top vulnerabilities
    if (auditResult.vulnerabilities.length > 0) {
      console.log('\n🚨 Top Vulnerabilities:');
      auditResult.vulnerabilities
        .slice(0, 5)
        .forEach((vuln: any, index: number) => {
          const severityIcon = this.getSeverityIcon(vuln.severity);
          console.log(`   ${index + 1}. ${severityIcon} ${vuln.description}`);
          if (vuln.file) {
            console.log(`      📄 ${vuln.file}:${vuln.line || '?'}`);
          }
          console.log(`      💡 ${vuln.recommendation}`);
          console.log('');
        });
    }

    // Recommendations
    if (auditResult.summary.total > 0) {
      console.log('\n💡 Recommendations:');
      console.log('   1. Fix critical and high severity vulnerabilities immediately');
      console.log('   2. Review and update dependencies regularly');
      console.log('   3. Implement security headers and HTTPS');
      console.log('   4. Use input validation and output encoding');
      console.log('   5. Enable runtime security monitoring');
    } else {
      console.log('\n✅ No security vulnerabilities found!');
    }
  }

  private async generateOutputFiles(auditResult: any, dependencyReport?: any): Promise<void> {
    const outputPath = this.options.output || join(this.options.projectPath, 'security-audit-report');

    const reportData = {
      audit: auditResult,
      dependencies: dependencyReport,
      generatedAt: new Date().toISOString(),
      options: this.options,
    };

    switch (this.options.format) {
      case 'json':
        writeFileSync(`${outputPath}.json`, JSON.stringify(reportData, null, 2));
        console.log(`\n📄 JSON report saved to: ${outputPath}.json`);
        break;

      case 'html':
        const htmlReport = this.generateHTMLReport(reportData);
        writeFileSync(`${outputPath}.html`, htmlReport);
        console.log(`\n📄 HTML report saved to: ${outputPath}.html`);
        break;

      case 'markdown':
        const markdownReport = this.generateMarkdownReport(reportData);
        writeFileSync(`${outputPath}.md`, markdownReport);
        console.log(`\n📄 Markdown report saved to: ${outputPath}.md`);
        break;

      case 'csv':
        const csvReport = this.generateCSVReport(reportData);
        writeFileSync(`${outputPath}.csv`, csvReport);
        console.log(`\n📄 CSV report saved to: ${outputPath}.csv`);
        break;
    }
  }

  private async generateFixScript(dependencyReport: any): Promise<void> {
    const scanner = new VulnerabilityScanner({
      projectPath: this.options.projectPath,
    });

    const fixScript = await scanner.generateFixScript();
    const scriptPath = join(this.options.projectPath, 'fix-vulnerabilities.sh');

    writeFileSync(scriptPath, fixScript);
    console.log(`\n🔧 Fix script saved to: ${scriptPath}`);
    console.log('   Run with: chmod +x fix-vulnerabilities.sh && ./fix-vulnerabilities.sh');
  }

  private generateHTMLReport(data: any): string {
    return `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>OrdoJS Security Audit Report</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        .header { background: #f8f9fa; padding: 20px; border-radius: 8px; }
        .summary { display: flex; gap: 20px; margin: 20px 0; }
        .metric { background: #fff; border: 1px solid #ddd; padding: 15px; border-radius: 8px; }
        .vulnerability { border-left: 4px solid #dc3545; padding: 10px; margin: 10px 0; background: #f8f9fa; }
        .critical { border-left-color: #dc3545; }
        .high { border-left-color: #fd7e14; }
        .medium { border-left-color: #ffc107; }
        .low { border-left-color: #28a745; }
        .recommendation { background: #e7f3ff; padding: 10px; border-radius: 4px; margin: 5px 0; }
    </style>
</head>
<body>
    <div class="header">
        <h1>🛡️ OrdoJS Security Audit Report</h1>
        <p>Generated on: ${data.generatedAt}</p>
        <p>Project: ${this.options.projectPath}</p>
    </div>

    <div class="summary">
        <div class="metric">
            <h3>Total Vulnerabilities</h3>
            <h2>${data.audit.summary.total}</h2>
        </div>
        <div class="metric">
            <h3>OWASP Compliance</h3>
            <h2>${data.audit.owaspCompliance.score}%</h2>
        </div>
        ${data.dependencies ? `
        <div class="metric">
            <h3>Dependency Issues</h3>
            <h2>${data.dependencies.summary.total}</h2>
        </div>
        ` : ''}
    </div>

    <h2>🚨 Vulnerabilities</h2>
    ${data.audit.vulnerabilities.map((vuln: any) => `
    <div class="vulnerability ${vuln.severity}">
        <h4>${vuln.description}</h4>
        ${vuln.file ? `<p><strong>File:</strong> ${vuln.file}:${vuln.line || '?'}</p>` : ''}
        <p><strong>Severity:</strong> ${vuln.severity.toUpperCase()}</p>
        <p><strong>Type:</strong> ${vuln.type}</p>
        ${vuln.owaspCategory ? `<p><strong>OWASP:</strong> ${vuln.owaspCategory}</p>` : ''}
        <div class="recommendation">
            <strong>Recommendation:</strong> ${vuln.recommendation}
        </div>
    </div>
    `).join('')}

    ${data.dependencies && data.dependencies.vulnerabilities.length > 0 ? `
    <h2>📦 Dependency Vulnerabilities</h2>
    ${data.dependencies.vulnerabilities.map((vuln: any) => `
    <div class="vulnerability ${vuln.vulnerability.severity}">
        <h4>${vuln.package}@${vuln.version}</h4>
        <p><strong>Issue:</strong> ${vuln.vulnerability.title}</p>
        <p><strong>Severity:</strong> ${vuln.vulnerability.severity.toUpperCase()}</p>
        ${vuln.vulnerability.cvss ? `<p><strong>CVSS Score:</strong> ${vuln.vulnerability.cvss.score}</p>` : ''}
        <div class="recommendation">
            <strong>Fix:</strong> ${vuln.fixAvailable.available ?
              `Update to ${vuln.fixAvailable.version}` :
              'No automatic fix available'}
        </div>
    </div>
    `).join('')}
    ` : ''}
</body>
</html>
    `.trim();
  }

  private generateMarkdownReport(data: any): string {
    return `
# 🛡️ OrdoJS Security Audit Report

**Generated:** ${data.generatedAt}
**Project:** ${this.options.projectPath}

## 📊 Summary

- **Total Vulnerabilities:** ${data.audit.summary.total}
- **Critical:** ${data.audit.summary.critical}
- **High:** ${data.audit.summary.high}
- **Medium:** ${data.audit.summary.medium}
- **Low:** ${data.audit.summary.low}
- **OWASP Compliance Score:** ${data.audit.owaspCompliance.score}%

${data.dependencies ? `
## 📦 Dependency Vulnerabilities

- **Total:** ${data.dependencies.summary.total}
- **Critical:** ${data.dependencies.summary.critical}
- **High:** ${data.dependencies.summary.high}
- **Medium:** ${data.dependencies.summary.medium}
- **Low:** ${data.dependencies.summary.low}
` : ''}

## 🚨 Vulnerabilities

${data.audit.vulnerabilities.map((vuln: any) => `
### ${vuln.description}

- **Severity:** ${vuln.severity.toUpperCase()}
- **Type:** ${vuln.type}
${vuln.file ? `- **File:** ${vuln.file}:${vuln.line || '?'}` : ''}
${vuln.owaspCategory ? `- **OWASP Category:** ${vuln.owaspCategory}` : ''}

**Recommendation:** ${vuln.recommendation}

---
`).join('')}

${data.dependencies && data.dependencies.vulnerabilities.length > 0 ? `
## 📦 Dependency Issues

${data.dependencies.vulnerabilities.map((vuln: any) => `
### ${vuln.package}@${vuln.version}

- **Issue:** ${vuln.vulnerability.title}
- **Severity:** ${vuln.vulnerability.severity.toUpperCase()}
- **ID:** ${vuln.vulnerability.id}
${vuln.vulnerability.cvss ? `- **CVSS Score:** ${vuln.vulnerability.cvss.score}` : ''}

**Fix:** ${vuln.fixAvailable.available ?
  `Update to ${vuln.fixAvailable.version}` :
  'No automatic fix available'}

---
`).join('')}
` : ''}
    `.trim();
  }

  private generateCSVReport(data: any): string {
    const headers = ['Type', 'Severity', 'Description', 'File', 'Line', 'Recommendation', 'OWASP Category'];
    const rows = data.audit.vulnerabilities.map((vuln: any) => [
      vuln.type,
      vuln.severity,
      vuln.description,
      vuln.file || '',
      vuln.line || '',
      vuln.recommendation,
      vuln.owaspCategory || '',
    ]);

    return [headers, ...rows]
      .map(row => row.map((cell: any) => `"${cell}"`).join(','))
      .join('\n');
  }

  private getSeverityIcon(severity: string): string {
    switch (severity) {
      case 'critical': return '🔴';
      case 'high': return '🟠';
      case 'medium': return '🟡';
      case 'low': return '🟢';
      default: return '⚪';
    }
  }
}

// CLI argument parsing
function parseArgs(): CLIOptions {
  const args = process.argv.slice(2);
  const options: CLIOptions = {
    projectPath: process.cwd(),
  };

  for (let i = 0; i < args.length; i++) {
    const arg = args[i];
    const nextArg = args[i + 1];

    switch (arg) {
      case '--path':
      case '-p':
        if (nextArg) options.projectPath = nextArg;
        i++;
        break;
      case '--output':
      case '-o':
        if (nextArg) options.output = nextArg;
        i++;
        break;
      case '--format':
      case '-f':
        options.format = nextArg as any;
        i++;
        break;
      case '--severity':
      case '-s':
        options.severity = nextArg as any;
        i++;
        break;
      case '--no-deps':
        options.enableDependencyCheck = false;
        break;
      case '--no-code':
        options.enableCodeAnalysis = false;
        break;
      case '--no-config':
        options.enableConfigurationCheck = false;
        break;
      case '--fix':
        options.generateFixScript = true;
        break;
      case '--verbose':
      case '-v':
        options.verbose = true;
        break;
      case '--help':
      case '-h':
        console.log(`
OrdoJS Security Audit CLI

Usage: ordojs-security-audit [options]

Options:
  -p, --path <path>        Project path (default: current directory)
  -o, --output <file>      Output file path
  -f, --format <format>    Output format: json, html, markdown, csv (default: json)
  -s, --severity <level>   Minimum severity: low, medium, high, critical (default: low)
  --no-deps               Skip dependency vulnerability check
  --no-code               Skip source code analysis
  --no-config             Skip configuration audit
  --fix                   Generate vulnerability fix script
  -v, --verbose           Verbose output
  -h, --help              Show this help message

Examples:
  ordojs-security-audit
  ordojs-security-audit --path ./my-project --format html --output report
  ordojs-security-audit --severity high --fix --verbose
        `);
        process.exit(0);
    }
  }

  return options;
}

// Run CLI if this file is executed directly
if (require.main === module) {
  const options = parseArgs();
  const cli = new SecurityAuditCLI(options);
  cli.run().catch(console.error);
}

export { SecurityAuditCLI };
export type { CLIOptions };

