// Detector Loader - Dynamically loads and registers all detector modules
// Automatically discovers detectors from directory structure

export class DetectorLoader {
  constructor(analyzerEngine) {
    this.engine = analyzerEngine;
    this.loadedCount = 0;
    this.failedCount = 0;
    this.detectorManifest = this.getDetectorManifest();
  }

  /**
   * Get detector manifest - all detectors organized by category
   * @returns {object} - Detector manifest
   */
  getDetectorManifest() {
    return {
      'url-detectors': [
        'domain-reputation',
        'lookalike-domain',
        'typosquatting'
      ],
      'social-engineering': [
        'command-pattern',
        'clickjacking',
        'fake-chrome',
        'browser-in-browser',
        'tabnabbing',
        'dialog-trap'
      ],
      'code-injection': [
        'html-smuggling',
        'formjacking',
        'malvertising',
        'wasm-mining',
        'xss-detector'
      ],
      'data-theft': [
        'clipboard-poisoning',
        'exfil-channel',
        'autofill-harvesting',
        'overlay-credential',
        'session-hijacking'
      ],
      'malicious-extensions': [
        'permission-drift',
        'overbroad-permissions'
      ],
      'cross-site': [
        'csrf-detector',
        'private-network',
        'jsonp-detector'
      ],
      'resource-detectors': [
        'mime-type-analysis',
        'extension-analysis'
      ],
      'permission-detectors': [
        'high-risk-permissions'
      ]
    };
  }

  /**
   * Load all detectors from all categories
   */
  async loadAllDetectors() {
    console.log('[DetectorLoader] Loading all detectors...');

    const categories = Object.keys(this.detectorManifest);

    for (const category of categories) {
      await this.loadCategory(category);
    }

    console.log(`[DetectorLoader] Loaded ${this.loadedCount} detectors, ${this.failedCount} failed`);
  }

  /**
   * Load all detectors from a category
   * @param {string} category - Category name
   */
  async loadCategory(category) {
    const detectors = this.detectorManifest[category];

    if (!detectors || detectors.length === 0) {
      console.warn(`[DetectorLoader] No detectors found for category: ${category}`);
      return;
    }

    console.log(`[DetectorLoader] Loading ${category}...`);

    for (const detectorName of detectors) {
      await this.loadDetector(category, detectorName);
    }
  }

  /**
   * Load individual detector
   * @param {string} category - Category name
   * @param {string} detectorName - Detector name
   */
  async loadDetector(category, detectorName) {
    try {
      // Construct detector path
      const detectorPath = `../detectors/${category}/${detectorName}.js`;

      // Dynamic import
      const module = await import(detectorPath);

      // Get detector class (PascalCase from kebab-case)
      const className = this.toPascalCase(detectorName);
      const DetectorClass = module[className];

      if (!DetectorClass) {
        throw new Error(`Detector class ${className} not found in module`);
      }

      // Instantiate detector
      const detectorInstance = new DetectorClass();

      // Register with engine
      this.engine.registerDetector(detectorName, detectorInstance);

      this.loadedCount++;

    } catch (error) {
      console.error(`[DetectorLoader] Failed to load ${category}/${detectorName}:`, error);
      this.failedCount++;
    }
  }

  /**
   * Convert kebab-case to PascalCase
   * @param {string} str - kebab-case string
   * @returns {string} - PascalCase string
   */
  toPascalCase(str) {
    return str
      .split('-')
      .map(word => word.charAt(0).toUpperCase() + word.slice(1))
      .join('');
  }

  /**
   * Load detectors for specific categories only
   * @param {array} categories - Array of category names
   */
  async loadCategories(categories) {
    console.log(`[DetectorLoader] Loading categories: ${categories.join(', ')}`);

    for (const category of categories) {
      await this.loadCategory(category);
    }

    console.log(`[DetectorLoader] Loaded ${this.loadedCount} detectors from selected categories`);
  }

  /**
   * Reload a detector (for hot-reload/testing)
   * @param {string} category - Category name
   * @param {string} detectorName - Detector name
   */
  async reloadDetector(category, detectorName) {
    console.log(`[DetectorLoader] Reloading ${category}/${detectorName}...`);

    // Unregister existing
    if (this.engine.detectors.has(detectorName)) {
      this.engine.detectors.delete(detectorName);
    }

    // Reload
    await this.loadDetector(category, detectorName);
  }

  /**
   * Get load statistics
   * @returns {object} - Load stats
   */
  getStats() {
    return {
      loaded: this.loadedCount,
      failed: this.failedCount,
      total: this.loadedCount + this.failedCount,
      successRate: this.loadedCount / (this.loadedCount + this.failedCount)
    };
  }

  /**
   * Validate detector manifest against actual filesystem
   * (For debugging/development)
   */
  async validateManifest() {
    console.log('[DetectorLoader] Validating manifest...');

    const issues = [];

    for (const [category, detectors] of Object.entries(this.detectorManifest)) {
      for (const detectorName of detectors) {
        const detectorPath = `../detectors/${category}/${detectorName}.js`;

        try {
          await import(detectorPath);
        } catch (error) {
          issues.push({
            category,
            detector: detectorName,
            path: detectorPath,
            error: error.message
          });
        }
      }
    }

    if (issues.length > 0) {
      console.warn(`[DetectorLoader] Found ${issues.length} manifest issues:`, issues);
    } else {
      console.log('[DetectorLoader] Manifest validation passed');
    }

    return {
      valid: issues.length === 0,
      issues
    };
  }
}
