// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import type { 
  KernelSecurityVulnerability,
  KernelSecurityScanResult
} from '@objectstack/spec/kernel';
import type { ObjectLogger } from '../logger.js';

/**
 * Scan Target
 */
export interface ScanTarget {
  pluginId: string;
  version: string;
  files?: string[];
  dependencies?: Record<string, string>;
}

/**
 * Security Issue
 */
export interface SecurityIssue {
  id: string;
  severity: 'critical' | 'high' | 'medium' | 'low' | 'info';
  category: 'vulnerability' | 'malware' | 'license' | 'code-quality' | 'configuration';
  title: string;
  description: string;
  location?: {
    file?: string;
    line?: number;
    column?: number;
  };
  remediation?: string;
  cve?: string;
  cvss?: number;
}

/**
 * Plugin Security Scanner
 * 
 * Scans plugins for security vulnerabilities, malware, and license issues
 */
export class PluginSecurityScanner {
  private logger: ObjectLogger;
  
  // Known vulnerabilities database (CVE cache)
  private vulnerabilityDb = new Map<string, KernelSecurityVulnerability>();
  
  // Scan results cache
  private scanResults = new Map<string, KernelSecurityScanResult>();

  private passThreshold: number = 70;

  constructor(logger: ObjectLogger, config?: { passThreshold?: number }) {
    this.logger = logger.child({ component: 'SecurityScanner' });
    if (config?.passThreshold !== undefined) {
      this.passThreshold = config.passThreshold;
    }
  }

  /**
   * Perform a comprehensive security scan on a plugin
   */
  async scan(target: ScanTarget): Promise<KernelSecurityScanResult> {
    this.logger.info('Starting security scan', { 
      pluginId: target.pluginId,
      version: target.version 
    });

    const issues: SecurityIssue[] = [];

    try {
      // 1. Scan for code vulnerabilities
      const codeIssues = await this.scanCode(target);
      issues.push(...codeIssues);

      // 2. Scan dependencies for known vulnerabilities
      const depIssues = await this.scanDependencies(target);
      issues.push(...depIssues);

      // 3. Scan for malware patterns
      const malwareIssues = await this.scanMalware(target);
      issues.push(...malwareIssues);

      // 4. Check license compliance
      const licenseIssues = await this.scanLicenses(target);
      issues.push(...licenseIssues);

      // 5. Check configuration security
      const configIssues = await this.scanConfiguration(target);
      issues.push(...configIssues);

      // Calculate security score (0-100, higher is better)
      const score = this.calculateSecurityScore(issues);

      const result: KernelSecurityScanResult = {
        timestamp: new Date().toISOString(),
        scanner: { name: 'ObjectStack Security Scanner', version: '1.0.0' },
        status: score >= this.passThreshold ? 'passed' : 'failed',
        vulnerabilities: issues.map(issue => ({
          id: issue.id,
          severity: issue.severity,
          category: issue.category,
          title: issue.title,
          description: issue.description,
          location: issue.location ? `${issue.location.file}:${issue.location.line}` : undefined,
          remediation: issue.remediation,
          affectedVersions: [],
          exploitAvailable: false,
          patchAvailable: false,
        })),
        summary: {
          totalVulnerabilities: issues.length,
          criticalCount: issues.filter(i => i.severity === 'critical').length,
          highCount: issues.filter(i => i.severity === 'high').length,
          mediumCount: issues.filter(i => i.severity === 'medium').length,
          lowCount: issues.filter(i => i.severity === 'low').length,
          infoCount: issues.filter(i => i.severity === 'info').length,
        },
      };

      this.scanResults.set(`${target.pluginId}:${target.version}`, result);

      this.logger.info('Security scan complete', { 
        pluginId: target.pluginId,
        score,
        status: result.status,
        summary: result.summary
      });

      return result;
    } catch (error) {
      this.logger.error('Security scan failed', { 
        pluginId: target.pluginId, 
        error 
      });

      throw error;
    }
  }

  /**
   * Scan code for vulnerabilities
   */
  private async scanCode(target: ScanTarget): Promise<SecurityIssue[]> {
    const issues: SecurityIssue[] = [];

    // In a real implementation, this would:
    // - Parse code with AST (e.g., using @typescript-eslint/parser)
    // - Check for dangerous patterns (eval, Function constructor, etc.)
    // - Check for XSS vulnerabilities
    // - Check for SQL injection patterns
    // - Check for insecure crypto usage
    // - Check for path traversal vulnerabilities

    this.logger.debug('Code scan complete', { 
      pluginId: target.pluginId,
      issuesFound: issues.length 
    });

    return issues;
  }

  /**
   * Scan dependencies for known vulnerabilities
   */
  private async scanDependencies(target: ScanTarget): Promise<SecurityIssue[]> {
    const issues: SecurityIssue[] = [];

    if (!target.dependencies) {
      return issues;
    }

    // In a real implementation, this would:
    // - Query npm audit API
    // - Check GitHub Advisory Database
    // - Check Snyk vulnerability database
    // - Check OSV (Open Source Vulnerabilities)

    for (const [depName, version] of Object.entries(target.dependencies)) {
      const vulnKey = `${depName}@${version}`;
      const vulnerability = this.vulnerabilityDb.get(vulnKey);

      if (vulnerability) {
        issues.push({
          id: `vuln-${vulnerability.cve || depName}`,
          severity: vulnerability.severity,
          category: 'vulnerability',
          title: `Vulnerable dependency: ${depName}`,
          description: `${depName}@${version} has known security vulnerabilities`,
          remediation: vulnerability.fixedIn 
            ? `Upgrade to ${vulnerability.fixedIn.join(' or ')}`
            : 'No fix available',
          cve: vulnerability.cve,
        });
      }
    }

    this.logger.debug('Dependency scan complete', { 
      pluginId: target.pluginId,
      dependencies: Object.keys(target.dependencies).length,
      vulnerabilities: issues.length 
    });

    return issues;
  }

  /**
   * Scan for malware patterns
   */
  private async scanMalware(target: ScanTarget): Promise<SecurityIssue[]> {
    const issues: SecurityIssue[] = [];

    // In a real implementation, this would:
    // - Check for obfuscated code
    // - Check for suspicious network activity patterns
    // - Check for crypto mining patterns
    // - Check for data exfiltration patterns
    // - Use ML-based malware detection
    // - Check file hashes against known malware databases

    this.logger.debug('Malware scan complete', { 
      pluginId: target.pluginId,
      issuesFound: issues.length 
    });

    return issues;
  }

  /**
   * Check license compliance
   */
  private async scanLicenses(target: ScanTarget): Promise<SecurityIssue[]> {
    const issues: SecurityIssue[] = [];

    if (!target.dependencies) {
      return issues;
    }

    // In a real implementation, this would:
    // - Check license compatibility
    // - Detect GPL contamination
    // - Flag proprietary dependencies
    // - Check for missing licenses
    // - Verify SPDX identifiers

    this.logger.debug('License scan complete', { 
      pluginId: target.pluginId,
      issuesFound: issues.length 
    });

    return issues;
  }

  /**
   * Check configuration security
   */
  private async scanConfiguration(target: ScanTarget): Promise<SecurityIssue[]> {
    const issues: SecurityIssue[] = [];

    // In a real implementation, this would:
    // - Check for hardcoded secrets
    // - Check for weak permissions
    // - Check for insecure defaults
    // - Check for missing security headers
    // - Check CSP policies

    this.logger.debug('Configuration scan complete', { 
      pluginId: target.pluginId,
      issuesFound: issues.length 
    });

    return issues;
  }

  /**
   * Calculate security score based on issues
   */
  private calculateSecurityScore(issues: SecurityIssue[]): number {
    // Start with perfect score
    let score = 100;

    // Deduct points based on severity
    for (const issue of issues) {
      switch (issue.severity) {
        case 'critical':
          score -= 20;
          break;
        case 'high':
          score -= 10;
          break;
        case 'medium':
          score -= 5;
          break;
        case 'low':
          score -= 2;
          break;
        case 'info':
          score -= 0;
          break;
      }
    }

    // Ensure score doesn't go below 0
    return Math.max(0, score);
  }

  /**
   * Add a vulnerability to the database
   */
  addVulnerability(
    packageName: string,
    version: string,
    vulnerability: KernelSecurityVulnerability
  ): void {
    const key = `${packageName}@${version}`;
    this.vulnerabilityDb.set(key, vulnerability);
    
    this.logger.debug('Vulnerability added to database', { 
      package: packageName, 
      version,
      cve: vulnerability.cve 
    });
  }

  /**
   * Get scan result from cache
   */
  getScanResult(pluginId: string, version: string): KernelSecurityScanResult | undefined {
    return this.scanResults.get(`${pluginId}:${version}`);
  }

  /**
   * Clear scan results cache
   */
  clearCache(): void {
    this.scanResults.clear();
    this.logger.debug('Scan results cache cleared');
  }

  /**
   * Update vulnerability database from external source
   */
  async updateVulnerabilityDatabase(): Promise<void> {
    this.logger.info('Updating vulnerability database');

    // In a real implementation, this would:
    // - Fetch from GitHub Advisory Database
    // - Fetch from npm audit
    // - Fetch from NVD (National Vulnerability Database)
    // - Parse and cache vulnerability data

    this.logger.info('Vulnerability database updated', { 
      entries: this.vulnerabilityDb.size 
    });
  }

  /**
   * Shutdown security scanner
   */
  shutdown(): void {
    this.vulnerabilityDb.clear();
    this.scanResults.clear();
    
    this.logger.info('Security scanner shutdown complete');
  }
}
