import { Injectable, Logger } from '@nestjs/common';
import { BrokenAccessControlService } from './all-owasp-scan-module/broken-access-control/access-control.service';
import { CryptoTestService } from './all-owasp-scan-module/crypto-failure-test/crypto-test.service';
import { CombinedOwaspResults, FormattedAccessControlResult } from './interface/owasp-results.interface';
import { TestResult as AccessControlTestResult } from './all-owasp-scan-module/broken-access-control/interface/access-control.interface';

@Injectable()
export class OwaspService {
  private readonly logger = new Logger(OwaspService.name);

  constructor(
    private readonly accessControlService: BrokenAccessControlService,
    private readonly cryptoTestService: CryptoTestService,
  ) {}

  /**
   * Runs both broken access control and cryptographic failure scans in parallel.
   * @param url The target URL to scan.
   * @returns A combined report of both scans.
   */
  async runAllScans(url: string): Promise<CombinedOwaspResults> {
    this.logger.log(`Starting combined OWASP scan for: ${url}`);

    // Run both service tests in parallel for better performance
    const [accessControlRawResults, cryptoResults] = await Promise.all([
      this.accessControlService.runAllTests(url),
      this.cryptoTestService.runTest(url),
    ]);

    // Format the access control results
    const accessControlFormattedResults = this.formatAccessControlResults(url, accessControlRawResults);

    // Calculate a combined summary
    const totalVulnerabilities = accessControlFormattedResults.summary.vulnerabilitiesFound + cryptoResults.failed.length;
    const criticalCount = accessControlFormattedResults.summary.criticalIssues + cryptoResults.failed.filter(f => f.test.includes('Protocol') || f.test.includes('HSTS')).length;
    const highCount = accessControlFormattedResults.summary.highIssues + cryptoResults.failed.filter(f => !f.test.includes('Protocol') && !f.test.includes('HSTS')).length;
    const mediumCount = accessControlFormattedResults.summary.mediumIssues + cryptoResults.warnings.length;

    this.logger.log(`Combined scan completed for: ${url}`);

    return {
      url,
      scanDate: new Date().toISOString(),
      summary: {
        totalVulnerabilities,
        critical: criticalCount,
        high: highCount,
        medium: mediumCount,
        low: accessControlFormattedResults.summary.lowIssues,
      },
      results: {
        brokenAccessControl: accessControlFormattedResults,
        cryptographicFailures: cryptoResults,
      },
    };
  }

  /**
   * Formats raw access control results into a structured report.
   */
  private formatAccessControlResults(url: string, results: AccessControlTestResult[]): FormattedAccessControlResult {
    if (!results || results.length === 0) {
      return {
        url,
        summary: { totalTests: 0, vulnerabilitiesFound: 0, secureEndpoints: 0, criticalIssues: 0, highIssues: 0, mediumIssues: 0, lowIssues: 0 },
        vulnerabilities: { critical: [], high: [], medium: [], low: [] },
        secure: [],
      };
    }

    const vulnerabilities = results.filter(r => r.success);
    const secure = results.filter(r => !r.success);

    const critical = vulnerabilities.filter(v => v.severity === 'critical');
    const high = vulnerabilities.filter(v => v.severity === 'High');
    const medium = vulnerabilities.filter(v => v.severity === 'Medium');
    const low = vulnerabilities.filter(v => v.severity === 'Low');

    return {
      url: url,
      summary: {
        totalTests: results.length,
        vulnerabilitiesFound: vulnerabilities.length,
        secureEndpoints: secure.length,
        criticalIssues: critical.length,
        highIssues: high.length,
        mediumIssues: medium.length,
        lowIssues: low.length,
      },
      vulnerabilities: { critical, high, medium, low },
      secure,
    };
  }
}