import { SecurityHeader, SecurityResults, SecurityIssue } from './types';
import axios from 'axios';

export interface HeaderStatusResult {
  header: string;
  status: 'present' | 'missing' | 'invalid';
  value: string | null;
  recommendation: string;
  severity: 'critical' | 'high' | 'medium' | 'low' | 'info';
}

export class HeaderChecker {
  private securityHeaders: SecurityHeader[];
  private blacklistProviders: { name: string; endpoint: string }[];

  constructor() {
    this.securityHeaders = [
      {
        name: 'X-Frame-Options',
        expected: /^(DENY|SAMEORIGIN)$/i,
        recommendation: 'Set X-Frame-Options to "DENY" or "SAMEORIGIN" to prevent clickjacking attacks'
      },
      {
        name: 'X-Content-Type-Options',
        expected: /^nosniff$/i,
        recommendation: 'Set X-Content-Type-Options to "nosniff" to prevent MIME type sniffing attacks'
      },
      {
        name: 'Referrer-Policy',
        expected: /^(no-referrer|no-referrer-when-downgrade|origin|origin-when-cross-origin|same-origin|strict-origin|strict-origin-when-cross-origin)$/i,
        recommendation: 'Set a strict Referrer-Policy (e.g., "strict-origin-when-cross-origin") to control how much referrer information is included with requests'
      },
      {
        name: 'Strict-Transport-Security',
        expected: /^max-age=(\d+)(?:;\s*includeSubDomains)?(?:;\s*preload)?$/i,
        recommendation: 'Set Strict-Transport-Security to "max-age=31536000; includeSubDomains; preload" to enforce HTTPS connections'
      },
      {
        name: 'Content-Security-Policy',
        expected: /default-src|script-src|style-src|img-src|connect-src|font-src|object-src|media-src|frame-src|base-uri|form-action/i,
        recommendation: 'Implement a comprehensive Content-Security-Policy that defines allowed sources for all content types to prevent XSS and other injection attacks'
      },
      {
        name: 'Permissions-Policy',
        expected: /.+/i, // At minimum, any non-empty value
        recommendation: 'Implement a Permissions-Policy to restrict access to sensitive browser features (e.g., camera, microphone, geolocation)'
      },
      {
        name: 'Access-Control-Allow-Origin',
        expected: /^(https?:\/\/[\w\.-]+|\*)$/i,
        recommendation: 'Set specific allowed origins instead of wildcard (*) to prevent cross-origin attacks'
      },
      {
        name: 'Cross-Origin-Resource-Policy',
        expected: /^(same-origin|same-site|cross-origin)$/i,
        recommendation: 'Implement Cross-Origin-Resource-Policy with "same-origin" or "same-site" value for better resource isolation'
      },
      {
        name: 'Cross-Origin-Opener-Policy',
        expected: /^(same-origin|same-origin-allow-popups|unsafe-none)$/i,
        recommendation: 'Implement Cross-Origin-Opener-Policy with "same-origin" value to prevent window reference leaks'
      },
      {
        name: 'Cross-Origin-Embedder-Policy',
        expected: /^(require-corp|credentialless|unsafe-none)$/i,
        recommendation: 'Implement Cross-Origin-Embedder-Policy with "require-corp" to ensure resources are explicitly allowed'
      },
    ];

    // Initialize blacklist providers
    this.blacklistProviders = [
      {
        name: 'Google Safe Browsing',
        endpoint: 'https://safebrowsing.googleapis.com/v4/threatMatches:find'
      },
      // Add more blacklist providers as needed
    ];
  }

  /**
   * Main method to check headers and populate security results
   * @param headers Headers from HTTP response
   * @param results SecurityResults object to populate
   */
  check(headers: Headers, results: SecurityResults): void {
    // Check if the protocol is HTTP instead of HTTPS
    if (!results.url.toLowerCase().startsWith('https://')) {
      this.addIssue(results, 'critical_vulnerability', 'critical',
        'Website using insecure HTTP protocol',
        'Implement HTTPS with proper SSL/TLS certificates to encrypt traffic',
        'HTTP connections transmit data in plaintext, making them vulnerable to eavesdropping, data theft, and man-in-the-middle attacks');
    }

    const normalizedHeaders = this.normalizeHeaders(headers);
    const headerStatusResults: HeaderStatusResult[] = [];
    const presentHeaders: string[] = [];
    const missingHeaders: string[] = [];

    for (const header of this.securityHeaders) {
      const headerName = header.name.toLowerCase();
      const headerValue = normalizedHeaders[headerName] || null;

      // Store header value in findings for reference
      results.findings.headers[header.name] = headerValue;

      let status: 'present' | 'missing' | 'invalid' = 'present';
      let severity: SecurityIssue['severity'] = 'low';

      if (!headerValue) {
        status = 'missing';
        severity = this.getHeaderSeverity(header.name, 'missing');
        missingHeaders.push(header.name);
        this.addIssue(results, 'misconfiguration', severity,
          `Missing security header: ${header.name}`, header.recommendation);
      } else if (header.expected && !header.expected.test(headerValue)) {
        status = 'invalid';
        severity = this.getHeaderSeverity(header.name, 'invalid');
        this.addIssue(results, 'misconfiguration', severity,
          `Incorrect value for ${header.name}: ${headerValue}`, header.recommendation,
          this.getDetailedHeaderValidationMessage(header.name, headerValue));
      } else {
        presentHeaders.push(header.name);

        // Additional validation for specific headers
        if (header.name === 'Strict-Transport-Security') {
          this.validateHSTS(headerValue, results);
        } else if (header.name === 'Content-Security-Policy') {
          this.validateCSP(headerValue, results);
        } else if (header.name === 'Permissions-Policy') {
          this.validatePermissionsPolicy(headerValue, results);
        }
      }

      // Add to header status results for frontend
      headerStatusResults.push({
        header: header.name,
        status,
        value: headerValue,
        recommendation: header.recommendation,
        severity
      });
    }

    // Store header status results for frontend access
    results.findings.headerStatus = headerStatusResults;

    // Update summary with header information
    if (missingHeaders.length > 0) {
      results.summary.details.push(`Missing security headers: ${missingHeaders.join(', ')}`);
    }

    if (presentHeaders.length > 0) {
      results.summary.details.push(`Properly configured headers: ${presentHeaders.join(', ')}`);
    }

    // Add specific recommendations for key headers to summary
    const hsts = this.securityHeaders.find(h => h.name === 'Strict-Transport-Security');
    const csp = this.securityHeaders.find(h => h.name === 'Content-Security-Policy');
    const xfo = this.securityHeaders.find(h => h.name === 'X-Frame-Options');

    if (hsts && missingHeaders.includes(hsts.name)) {
      results.summary.details.push(hsts.recommendation);
    }

    if (csp && missingHeaders.includes(csp.name)) {
      results.summary.details.push(csp.recommendation);
    }

    if (xfo && missingHeaders.includes(xfo.name)) {
      results.summary.details.push(xfo.recommendation);
    }

    // Check cookie security
    this.checkCookieSecurity(headers, results);

    // Calculate overall status and severity
    this.calculateHeaderSecurityScore(results, headerStatusResults);

    // Check for deprecated headers
    this.checkDeprecatedHeaders(headers, results);

    // Check CORS policy
    this.checkCORSPolicy(headers, results);
  }

  /**
   * Get the severity level based on the header and issue type
   * @param headerName Name of the header
   * @param issueType Type of issue ('missing' or 'invalid')
   * @returns Appropriate severity level
   */
  private getHeaderSeverity(headerName: string, issueType: 'missing' | 'invalid'): SecurityIssue['severity'] {
    // Critical headers with high severity if missing
    const criticalHeaders = ['Content-Security-Policy', 'Strict-Transport-Security'];
    const highPriorityHeaders = ['X-Frame-Options', 'X-Content-Type-Options'];

    if (criticalHeaders.includes(headerName)) {
      return issueType === 'missing' ? 'high' : 'medium';
    } else if (highPriorityHeaders.includes(headerName)) {
      return issueType === 'missing' ? 'medium' : 'low';
    }

    return 'low';
  }

  /**
   * Get detailed validation message for specific headers
   * @param headerName Name of the header
   * @param value Current header value
   * @returns Detailed explanation of what's wrong with the value
   */
  private getDetailedHeaderValidationMessage(headerName: string, value: string): string {
    switch (headerName) {
      case 'X-Frame-Options':
        return `Value "${value}" is invalid. Only "DENY" or "SAMEORIGIN" are considered secure values. "ALLOW-FROM" is deprecated and not supported by modern browsers.`;

      case 'X-Content-Type-Options':
        return `Value "${value}" is invalid. The only valid value is "nosniff".`;

      case 'Strict-Transport-Security':
        if (!/max-age=\d+/i.test(value)) {
          return `HSTS header must include a max-age directive with a numeric value.`;
        }
        const maxAge = parseInt(value.match(/max-age=(\d+)/i)?.[1] || '0');
        if (maxAge < 31536000) {  // Less than 1 year
          return `HSTS max-age is set to ${maxAge} seconds. Recommended value is at least 31536000 seconds (1 year).`;
        }
        return `HSTS header should include "includeSubDomains" and "preload" directives for maximum security.`;

      case 'Content-Security-Policy':
        let issues = [];
        if (!/default-src/i.test(value)) {
          issues.push("missing 'default-src' directive");
        }
        if (/unsafe-inline|unsafe-eval/i.test(value)) {
          issues.push("contains unsafe 'unsafe-inline' or 'unsafe-eval' directives");
        }
        return `CSP is invalid or insufficient: ${issues.join(', ')}.`;

      case 'Referrer-Policy':
        return `Value "${value}" is not an optimal Referrer-Policy. Recommended values include "no-referrer", "no-referrer-when-downgrade", "same-origin", "strict-origin", or "strict-origin-when-cross-origin".`;

      case 'Permissions-Policy':
        return `The Permissions-Policy value does not properly restrict sensitive browser features. Consider implementing restrictions for camera, microphone, geolocation, and other sensitive permissions.`;

      default:
        return `The value "${value}" does not meet security requirements.`;
    }
  }



  /**
   * Check for deprecated or potentially risky security headers
   * @param headers Headers from HTTP response
   * @param results SecurityResults object to populate
   */
  checkDeprecatedHeaders(headers: Headers, results: SecurityResults): void {
    const deprecatedHeaders = [
      {
        name: 'X-XSS-Protection',
        reason: 'Deprecated in favor of Content-Security-Policy',
        recommendation: 'Remove X-XSS-Protection header and implement a proper Content-Security-Policy instead'
      },
      {
        name: 'X-WebKit-CSP',
        reason: 'Deprecated in favor of Content-Security-Policy',
        recommendation: 'Remove X-WebKit-CSP header and use the standard Content-Security-Policy header'
      },
      {
        name: 'X-Content-Security-Policy',
        reason: 'Deprecated in favor of Content-Security-Policy',
        recommendation: 'Remove X-Content-Security-Policy header and use the standard Content-Security-Policy header'
      },
      {
        name: 'Public-Key-Pins',
        reason: 'Deprecated and potentially dangerous if misconfigured',
        recommendation: 'Remove Public-Key-Pins header and use Certificate Transparency instead'
      },
      {
        name: 'Expect-CT',
        reason: 'Deprecated as Certificate Transparency is now enforced by browsers',
        recommendation: 'Remove Expect-CT header as it is no longer necessary'
      }
    ];

    for (const header of deprecatedHeaders) {
      const headerValue = headers.get(header.name);

      if (headerValue) {
        this.addIssue(results, 'misconfiguration', 'medium',
          `Deprecated security header: ${header.name}`,
          header.recommendation,
          `${header.name} is ${header.reason}`);

        // Store header value in findings for reference
        results.findings.headers[header.name] = headerValue;
      }
    }
  }

  /**
   * Check CORS policy configuration
   * @param headers Headers from HTTP response
   * @param results SecurityResults object to populate
   */
  checkCORSPolicy(headers: Headers, results: SecurityResults): void {
    // Check for Access-Control-Allow-Origin
    const allowOrigin = headers.get('Access-Control-Allow-Origin');
    if (allowOrigin) {
      results.findings.cors = {
        'Access-Control-Allow-Origin': allowOrigin,
        'Access-Control-Allow-Methods': headers.get('Access-Control-Allow-Methods'),
        'Access-Control-Allow-Headers': headers.get('Access-Control-Allow-Headers'),
        'Access-Control-Allow-Credentials': headers.get('Access-Control-Allow-Credentials'),
        'Access-Control-Max-Age': headers.get('Access-Control-Max-Age'),
        'Access-Control-Expose-Headers': headers.get('Access-Control-Expose-Headers')
      };

      // Check for wildcard origin with credentials
      if (allowOrigin === '*' && headers.get('Access-Control-Allow-Credentials') === 'true') {
        this.addIssue(results, 'critical_vulnerability', 'high',
          'Dangerous CORS configuration',
          'Do not use wildcard origin (*) with Access-Control-Allow-Credentials: true',
          'This configuration is rejected by browsers and could lead to cross-origin attacks');
      }

      // Check for wildcard origin generally
      if (allowOrigin === '*') {
        this.addIssue(results, 'misconfiguration', 'medium',
          'Permissive CORS policy',
          'Specify exact domains in Access-Control-Allow-Origin instead of wildcard (*)',
          'Using wildcard origin allows any website to access your resources, potentially exposing sensitive data');
      }

      // Check for missing CORS headers when CORS is implemented
      if (!headers.get('Access-Control-Allow-Methods')) {
        this.addIssue(results, 'misconfiguration', 'low',
          'Incomplete CORS configuration: Missing Access-Control-Allow-Methods',
          'Specify allowed HTTP methods with Access-Control-Allow-Methods header',
          'Without specifying allowed methods, browsers may not handle preflight requests correctly');
      }
    }
  }

  /**
   * Perform detailed validation of HSTS header
   * @param value HSTS header value
   * @param results Security results to update
   */
  private validateHSTS(value: string, results: SecurityResults): void {
    const maxAgeMatch = value.match(/max-age=(\d+)/i);

    if (!maxAgeMatch) {
      this.addIssue(results, 'misconfiguration', 'medium',
        'Invalid HSTS max-age directive',
        'Set a proper max-age value for HSTS (recommended: max-age=31536000)',
        `HSTS header doesn't contain a valid max-age directive: ${value}`);
      return;
    }

    const maxAge = parseInt(maxAgeMatch[1]);

    if (maxAge < 31536000) {  // Less than 1 year
      this.addIssue(results, 'misconfiguration', 'low',
        'HSTS max-age too short',
        'Increase HSTS max-age to at least 31536000 seconds (1 year)',
        `Current HSTS max-age is ${maxAge} seconds, which is less than the recommended 1 year.`);
    }

    if (!/includeSubDomains/i.test(value)) {
      this.addIssue(results, 'misconfiguration', 'low',
        'HSTS missing includeSubDomains directive',
        'Add includeSubDomains directive to HSTS header',
        'Without includeSubDomains, subdomains remain vulnerable to SSL stripping attacks.');
    }

    if (!/preload/i.test(value)) {
      this.addIssue(results, 'misconfiguration', 'info',
        'HSTS missing preload directive',
        'Consider adding the preload directive to HSTS header',
        'The preload directive allows your domain to be hardcoded into browsers as HTTPS only.');
    }
  }

  /**
   * Perform detailed validation of CSP header
   * @param value CSP header value
   * @param results Security results to update
   */
  private validateCSP(value: string, results: SecurityResults): void {
    // Check for essential directives
    const essentialDirectives = ['default-src', 'script-src', 'style-src'];
    const missingDirectives = essentialDirectives.filter(directive => !new RegExp(`${directive}\\s`, 'i').test(value));

    if (missingDirectives.length > 0) {
      this.addIssue(results, 'misconfiguration', 'medium',
        'CSP missing essential directives',
        `Enhance CSP by adding these essential directives: ${missingDirectives.join(', ')}`,
        'A robust CSP should define restrictions for all critical resource types.');
    }

    // Check for unsafe values
    if (/unsafe-inline/i.test(value)) {
      this.addIssue(results, 'misconfiguration', 'medium',
        'CSP contains unsafe-inline directive',
        'Remove unsafe-inline from CSP and use nonces or hashes instead',
        'The unsafe-inline directive undermines protection against XSS attacks.');
    }

    if (/unsafe-eval/i.test(value)) {
      this.addIssue(results, 'misconfiguration', 'medium',
        'CSP contains unsafe-eval directive',
        'Remove unsafe-eval from CSP and refactor code to avoid eval()',
        'The unsafe-eval directive allows potentially dangerous code execution.');
    }

    // Check for wildcard sources
    const wildcardDirectives = value.split(';')
      .filter(directive => /\*$/.test(directive.trim()))
      .map(directive => directive.trim().split(/\s+/)[0]);

    if (wildcardDirectives.length > 0) {
      this.addIssue(results, 'misconfiguration', 'medium',
        'CSP contains wildcard sources',
        `Replace wildcard (*) sources in these directives: ${wildcardDirectives.join(', ')}`,
        'Wildcard sources significantly weaken the protection provided by CSP.');
    }

    // Check for report-uri/report-to
    if (!(/report-uri|report-to/i.test(value))) {
      this.addIssue(results, 'misconfiguration', 'info',
        'CSP missing reporting mechanism',
        'Add report-uri or report-to directive to CSP for violation reporting',
        'Without a reporting mechanism, you won\'t be notified of CSP violations.');
    }
  }

  /**
   * Perform detailed validation of Permissions-Policy header
   * @param value Permissions-Policy header value
   * @param results Security results to update
   */
  private validatePermissionsPolicy(value: string, results: SecurityResults): void {
    // Critical permissions that should be restricted
    const criticalPermissions = [
      'camera', 'microphone', 'geolocation', 'payment', 'usb',
      'clipboard-read', 'clipboard-write', 'screen-wake-lock'
    ];

    const missingPermissions = criticalPermissions.filter(permission =>
      !new RegExp(`${permission}=`, 'i').test(value)
    );

    if (missingPermissions.length > 0) {
      this.addIssue(results, 'misconfiguration', 'low',
        'Permissions-Policy missing critical permission restrictions',
        `Enhance Permissions-Policy by restricting these permissions: ${missingPermissions.join(', ')}`,
        'Without explicit restrictions, sensitive device features might be accessible to unauthorized content.');
    }

    // Check for overly permissive values (*)
    const permissivePermissions = criticalPermissions.filter(permission =>
      new RegExp(`${permission}=\\s*\\*`, 'i').test(value)
    );

    if (permissivePermissions.length > 0) {
      this.addIssue(results, 'misconfiguration', 'medium',
        'Permissions-Policy has overly permissive settings',
        `Restrict these permissions instead of allowing all origins (*): ${permissivePermissions.join(', ')}`,
        'Allowing all origins (*) access to sensitive permissions defeats the purpose of the Permissions-Policy.');
    }
  }

  /**
   * Calculate security score and set overall status based on headers
   * @param results Results object to update
   * @param headerResults Header check results
   */
  private calculateHeaderSecurityScore(results: SecurityResults, headerResults: HeaderStatusResult[]): void {
    const totalHeaders = this.securityHeaders.length;
    const criticalHeaders = ['Strict-Transport-Security', 'Content-Security-Policy', 'X-Frame-Options'];

    // Count missing critical headers
    const missingCriticalCount = headerResults
      .filter(h => criticalHeaders.includes(h.header) && h.status === 'missing')
      .length;

    // Count all missing or invalid headers
    const missingOrInvalidCount = headerResults
      .filter(h => h.status === 'missing' || h.status === 'invalid')
      .length;

    // Calculate percentage of properly configured headers
    const headerScore = Math.max(0, 10 - Math.floor((missingOrInvalidCount / totalHeaders) * 10));

    // Set severity based on score and critical headers
    let severity = headerScore;

    if (missingCriticalCount > 0) {
      // Increase severity if critical headers are missing
      severity = Math.max(7, severity);
    }

    if (!results.url.toLowerCase().startsWith('https://')) {
      // Highest severity if not using HTTPS
      severity = 10;
      results.headers.status = 'critical';
    } else if (severity >= 7) {
      results.headers.status = 'compromised';
    } else if (severity >= 4) {
      results.headers.status = 'vulnerable';
    } else if (severity >= 1) {
      results.headers.status = 'warning';
    } else {
      results.headers.status = 'secure';
    }

    results.headers.severity = severity;
  }

  /**
   * Check cookie security settings and add issues if necessary
   * @param headers Headers to check for cookies
   * @param results Results object to update
   */
  private checkCookieSecurity(headers: Headers, results: SecurityResults): void {
    const cookieHeader = headers.get('Set-Cookie');

    if (!cookieHeader) {
      return;
    }

    // Split multiple cookies
    const cookies = cookieHeader.split(/,(?=[^;]+=[^;]+)/);


    for (const cookie of cookies) {
      const isSecure = /secure/i.test(cookie);
      const isHttpOnly = /httponly/i.test(cookie);
      const hasSameSite = /samesite/i.test(cookie);
      const sameSiteValue = cookie.match(/samesite=([^;]+)/i)?.[1]?.toLowerCase();
      const cookieName = cookie.split('=')[0].trim();

      if (cookieName.startsWith('__Secure-') && !isSecure) {
        this.addIssue(results, 'misconfiguration', 'high',
          'Invalid __Secure- prefixed cookie',
          'Cookies with __Secure- prefix must have Secure flag',
          `Cookie '${cookieName}' uses __Secure- prefix without Secure flag`);
      }

      if (cookieName.startsWith('__Host-') && (!isSecure )) {
        this.addIssue(results, 'misconfiguration', 'high',
          'Invalid __Host- prefixed cookie',
          '__Host- cookies must be Secure, Path=/ and Domain-less',
          `Cookie '${cookieName}' violates __Host- prefix requirements`);
      }


      if (!isSecure) {
        this.addIssue(results, 'misconfiguration', 'medium',
          'Cookie missing Secure flag',
          'Add the Secure flag to all cookies to ensure they are only sent over HTTPS',
          `The following cookie is missing the Secure flag: ${cookie.split(';')[0]}`);
      }

      if (!isHttpOnly) {
        this.addIssue(results, 'misconfiguration', 'medium',
          'Cookie missing HttpOnly flag',
          'Add the HttpOnly flag to sensitive cookies to prevent JavaScript access',
          `The following cookie is missing the HttpOnly flag: ${cookie.split(';')[0]}`);
      }

      if (!hasSameSite) {
        this.addIssue(results, 'misconfiguration', 'medium',
          'Cookie missing SameSite attribute',
          'Set SameSite=Lax or SameSite=Strict on cookies to mitigate CSRF risks',
          `The following cookie is missing the SameSite attribute: ${cookie.split(';')[0]}`);
      } else if (sameSiteValue === 'none' && isSecure) {
        this.addIssue(results, 'misconfiguration', 'low',
          'Cookie uses SameSite=None',
          'Consider using SameSite=Lax or SameSite=Strict instead of SameSite=None',
          `The following cookie uses SameSite=None which may expose it to cross-site requests: ${cookie.split(';')[0]}`);
      }

      // Check for cookie expiration
      const maxAgeMatch = cookie.match(/max-age=(\d+)/i);
      const expiresMatch = cookie.match(/expires=([^;]+)/i);

      if (maxAgeMatch) {
        const maxAge = parseInt(maxAgeMatch[1]);
        if (maxAge > 31536000) { // More than a year
          this.addIssue(results, 'misconfiguration', 'low',
            'Cookie has excessive lifespan',
            'Reduce cookie lifetime to improve security and privacy',
            `Cookie has a max-age of ${maxAge} seconds (> 1 year): ${cookie.split(';')[0]}`);
        }
      } else if (expiresMatch) {
        try {
          const expiryDate = new Date(expiresMatch[1]);
          const oneYearFromNow = new Date();
          oneYearFromNow.setFullYear(oneYearFromNow.getFullYear() + 1);

          if (expiryDate > oneYearFromNow) {
            this.addIssue(results, 'misconfiguration', 'low',
              'Cookie has excessive lifespan',
              'Reduce cookie lifetime to improve security and privacy',
              `Cookie expires far in the future (> 1 year): ${cookie.split(';')[0]}`);
          }
        } catch (e) {
          // Invalid date format, ignore
        }
      }
    }
  }

  /**
   * Normalize headers to lowercase for consistent lookup
   * @param headers Headers object
   * @returns Record with lowercase header names
   */
  private normalizeHeaders(headers: Headers): Record<string, string> {
    const normalized: Record<string, string> = {};
    headers.forEach((value, key) => {
      normalized[key.toLowerCase()] = value;
    });
    return normalized;
  }

  /**
   * Add a security issue to the results
   * @param results Results object to update
   * @param type Issue type
   * @param severity Issue severity
   * @param title Issue title
   * @param recommendation How to fix the issue
   * @param details Additional details
   */
  private addIssue(
    results: SecurityResults,
    type: string,
    severity: SecurityIssue['severity'],
    title: string,
    recommendation: string,
    details?: string
  ): void {
    results.issues.push({
      type,
      severity,
      title,
      recommendation,
      details
    });

    // Update summary counters according to severity
    switch (severity) {
      case 'critical':
        results.summary.criticalIssues++;
        break;
      case 'high':
        results.summary.highIssues++;
        break;
      case 'medium':
        results.summary.mediumIssues++;
        break;
      case 'low':
        results.summary.lowIssues++;
        break;
      case 'info':
        results.summary.infos++;
        break;
    }
  }

  /**
   * Generate a comprehensive report of header security status
   * @param headers The headers from the HTTP response
   * @returns A formatted header security report
   */
  generateHeaderReport(headers: Headers): {
    overallStatus: string;
    score: number;
    headers: HeaderStatusResult[];
    recommendations: string[];
  } {
    const headerResults: HeaderStatusResult[] = [];
    const recommendations: string[] = [];
    let missingCount = 0;
    let invalidCount = 0;

    for (const header of this.securityHeaders) {
      const headerValue = headers.get(header.name);

      let status: 'present' | 'missing' | 'invalid' = 'present';
      let severity: SecurityIssue['severity'] = 'low';

      if (!headerValue) {
        status = 'missing';
        severity = this.getHeaderSeverity(header.name, 'missing');
        missingCount++;
        recommendations.push(header.recommendation);
      } else if (header.expected && !header.expected.test(headerValue)) {
        status = 'invalid';
        severity = this.getHeaderSeverity(header.name, 'invalid');
        invalidCount++;
        recommendations.push(header.recommendation);
      }

      headerResults.push({
        header: header.name,
        status,
        value: headerValue || null,
        recommendation: header.recommendation,
        severity
      });
    }

    // Calculate score (0-100, higher is better)
    const totalHeaders = this.securityHeaders.length;
    const presentHeaders = totalHeaders - missingCount - invalidCount;
    const score = Math.round((presentHeaders / totalHeaders) * 100);

    // Determine overall status
    let overallStatus = 'secure';
    if (score < 50) {
      overallStatus = 'critical';
    } else if (score < 70) {
      overallStatus = 'high-risk';
    } else if (score < 90) {
      overallStatus = 'medium-risk';
    } else if (score < 100) {
      overallStatus = 'low-risk';
    }

    return {
      overallStatus,
      score,
      headers: headerResults,
      recommendations
    };
  }

  /**
   * Check if the domain is blacklisted by known security blacklists
   * @param url The URL to check
   * @param results The results object to update with blacklist findings
   */
  async checkBlacklist(url: string, results: SecurityResults): Promise<void> {
    const { hostname } = new URL(url);

    try {
      // Initialize blacklist results array if it doesn't exist
      if (!results.findings.blacklists) {
        results.findings.blacklists = [];
      }

      // Check with Google Safe Browsing API
      const SAFE_BROWSING_API_KEY = process.env.GOOGLE_SAFE_BROWSING_API_KEY;

      if (!SAFE_BROWSING_API_KEY) {
        this.addIssue(results, 'warning', 'info',
          'Blacklist check skipped',
          'Configure Google Safe Browsing API key for blacklist checks',
          'No API key available for Google Safe Browsing');
        return;
      }

      const blacklistResponse = await axios.post(
        `https://safebrowsing.googleapis.com/v4/threatMatches:find?key=${SAFE_BROWSING_API_KEY}`,
        {
          client: {
            clientId: 'website-security-checker',
            clientVersion: '1.5.2',
          },
          threatInfo: {
            threatTypes: ['MALWARE', 'SOCIAL_ENGINEERING', 'UNWANTED_SOFTWARE', 'POTENTIALLY_HARMFUL_APPLICATION'],
            platformTypes: ['ANY_PLATFORM'],
            threatEntryTypes: ['URL'],
            threatEntries: [{ url: hostname }],
          },
        }
      );

      // Check if website is blacklisted
      const matches = blacklistResponse.data.matches || [];
      if (matches.length > 0) {
        matches.forEach((match: any) => {
          results.findings.blacklists.push({
            provider: 'Google Safe Browsing',
            threatType: match.threatType,
            platformType: match.platformType,
            timestamp: new Date().toISOString()
          });

          this.addIssue(results, 'critical_vulnerability', 'critical',
            `Domain blacklisted by Google Safe Browsing as ${match.threatType}`,
            'Investigate and resolve the security issues detected by Google Safe Browsing',
            'Being listed in security blacklists can severely impact your website reputation and user trust');
        });
      }

    } catch (error) {
      this.addIssue(results, 'warning', 'medium',
        'Blacklist check failed',
        'Ensure connectivity to blacklist services',
        `Error checking blacklists: ${error.message}`);
    }
  }
}
