// Dynamic Rule Detector — Bridge between AnalyzerEngine and EnhancedRuleEngine
// Runs v2.0.0 enhanced rulesets against analysis targets as a standard detector.

import { BaseDetector } from '../detectors/base-detector.js';

export class DynamicRuleDetector extends BaseDetector {
  constructor(enhancedRuleEngine, ruleRegistry, config = {}) {
    super({
      name: 'dynamic-rule-v2',
      category: 'dynamic',
      version: '3.0.0',
      description: 'Evaluates v2/v3 enhanced dynamic rules',
      weight: 1,
      severity: 'medium',
      ...config,
    });

    this.enhancedEngine = enhancedRuleEngine;
    this.ruleRegistry = ruleRegistry;

    // v3: optional feature store and signal provider registry
    this.featureStore = config.featureStore || null;
    this.signalProviderRegistry = config.signalProviderRegistry || null;
  }

  /**
   * Set the FeatureStore for v3 rules.
   * @param {object} store - FeatureStore instance
   */
  setFeatureStore(store) {
    this.featureStore = store;
  }

  /**
   * Set the SignalProviderRegistry for v3 rules.
   * @param {object} registry - SignalProviderRegistry instance
   */
  setProviderRegistry(registry) {
    this.signalProviderRegistry = registry;
  }

  /**
   * Run all compiled v2 rulesets against the target.
   * @param {object} target - Analysis target from AnalyzerEngine
   * @param {object} ruleRegistry - RuleRegistry instance (passed by AnalyzerEngine)
   * @returns {object} Standard detection result { detector, matched, findings, riskScore }
   */
  async detect(target, ruleRegistry) {
    const findings = [];
    const technologies = [];

    // Get all enhanced rulesets from the registry
    const enhancedRulesets = (ruleRegistry || this.ruleRegistry).getEnhancedRulesets
      ? (ruleRegistry || this.ruleRegistry).getEnhancedRulesets()
      : [];

    // Also include any directly compiled rulesets in the engine
    const engineRulesets = this.enhancedEngine.getAllCompiledRulesets();

    // Merge, deduplicating by rulesetId
    const seen = new Set();
    const allRulesets = [];

    for (const rs of [...enhancedRulesets, ...engineRulesets]) {
      if (!seen.has(rs.rulesetId)) {
        seen.add(rs.rulesetId);
        allRulesets.push(rs);
      }
    }

    if (allRulesets.length === 0) {
      return this.createResult(false, [], 0);
    }

    // v3: build eval options with feature store and provider registry
    const evalOptions = {};
    if (this.featureStore) evalOptions.featureStore = this.featureStore;
    if (this.signalProviderRegistry) evalOptions.signalProviderRegistry = this.signalProviderRegistry;

    // Evaluate each ruleset
    for (const ruleset of allRulesets) {
      try {
        const result = this.enhancedEngine.evaluateRuleset(ruleset, target, evalOptions);

        // Convert detection findings to standard finding format
        for (const finding of result.findings) {
          findings.push(this.createFinding({
            pattern: finding.ruleId,
            matched: finding.description,
            description: finding.description,
            severity: finding.severity,
            weight: finding.weight,
            metadata: {
              rulesetId: finding.rulesetId,
              ruleName: finding.ruleName,
              action: finding.action,
              confidence: finding.confidence,
              type: 'enhanced-v2',
              ...finding.metadata,
            },
          }));
        }

        // Store technology fingerprints in findings metadata
        for (const tech of result.technologies) {
          technologies.push(tech);
        }
      } catch (error) {
        console.error(`[DynamicRuleDetector] Error evaluating ruleset ${ruleset.rulesetId}:`, error);
      }
    }

    const matched = findings.length > 0 || technologies.length > 0;
    const riskScore = findings.reduce((sum, f) => sum + (f.weight || 1), 0);

    const result = this.createResult(matched, findings, riskScore);

    // Attach technologies to the result for consumers that understand them
    result.technologies = technologies;

    return result;
  }
}
