/**
 * Risk Signature Manager
 * Predefined risk signatures for threat detection
 * CWE-778 Compliance: Logs all signature matches and management operations
 */

const logger = require('./logger');
const logAggregator = require('./logAggregator');
const { db } = require('../database/db');

class RiskSignatureManager {
  constructor() {
    this.signatures = new Map();
    this.initialize();
  }

  /**
   * Initialize risk signature manager
   */
  async initialize() {
    await this.createSignaturesTable();
    await this.loadSignatures();
    
    logger.info('[RiskSignatureManager] Initialized with predefined risk signatures');
    
    // Log initialization (CWE-778)
    logAggregator.aggregate('risk_signature_manager', 'info', 'security', 'Risk signature manager initialized', {
      totalSignatures: this.signatures.size
    });
  }

  /**
   * Create risk signatures table
   */
  async createSignaturesTable() {
    return new Promise((resolve, reject) => {
      db.run(`
        CREATE TABLE IF NOT EXISTS risk_signatures (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          signature_id TEXT UNIQUE NOT NULL,
          name TEXT NOT NULL,
          description TEXT,
          signature_type TEXT NOT NULL,
          pattern TEXT NOT NULL,
          match_type TEXT NOT NULL,
          threat_level TEXT NOT NULL,
          confidence REAL DEFAULT 0.8,
          enabled INTEGER DEFAULT 1,
          auto_block INTEGER DEFAULT 0,
          created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
          updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )
      `, async (err) => {
        if (err) reject(err);
        else {
          db.run(`CREATE INDEX IF NOT EXISTS idx_signatures_type ON risk_signatures(signature_type, enabled)`);
          db.run(`CREATE INDEX IF NOT EXISTS idx_signatures_threat ON risk_signatures(threat_level, enabled)`);
          await this.createDefaultSignatures();
          resolve();
        }
      });
    });
  }

  /**
   * Create default risk signatures
   */
  async createDefaultSignatures() {
    const defaultSignatures = [
      // IP-based signatures
      {
        signature_id: 'SIG-IP-TOR',
        name: 'TOR Exit Node',
        description: 'Known TOR exit node IP address',
        signature_type: 'ip_address',
        pattern: '(^10\\.\\d+\\.\\d+\\.\\d+|^172\\.(1[6-9]|2[0-9]|3[01])\\.\\d+\\.\\d+|^192\\.168\\.\\d+\\.\\d+)',
        match_type: 'regex',
        threat_level: 'high',
        confidence: 0.9,
        auto_block: 0
      },
      {
        signature_id: 'SIG-IP-SUSPICIOUS',
        name: 'Suspicious IP Range',
        description: 'IP from suspicious geographic region',
        signature_type: 'ip_address',
        pattern: '',
        match_type: 'custom',
        threat_level: 'medium',
        confidence: 0.7,
        auto_block: 0
      },
      // User-agent signatures
      {
        signature_id: 'SIG-UA-BOT-MALICIOUS',
        name: 'Malicious Bot User-Agent',
        description: 'Known malicious bot signatures',
        signature_type: 'user_agent',
        pattern: '(scrapy|python-requests|curl|wget|nikto|sqlmap|havij|acunetix|nessus|openvas)',
        match_type: 'regex_case_insensitive',
        threat_level: 'high',
        confidence: 0.95,
        auto_block: 1
      },
      {
        signature_id: 'SIG-UA-VULNERABILITY-SCANNER',
        name: 'Vulnerability Scanner',
        description: 'Automated vulnerability scanning tools',
        signature_type: 'user_agent',
        pattern: '(nmap|masscan|zap|burp|metasploit|w3af|arachni)',
        match_type: 'regex_case_insensitive',
        threat_level: 'critical',
        confidence: 0.99,
        auto_block: 1
      },
      // Attack pattern signatures
      {
        signature_id: 'SIG-ATTACK-SQL-INJECTION',
        name: 'SQL Injection Pattern',
        description: 'Common SQL injection attack patterns',
        signature_type: 'attack_pattern',
        pattern: '(union.*select|select.*from|insert.*into|delete.*from|drop.*table|exec.*xp_|script.*alert)',
        match_type: 'regex_case_insensitive',
        threat_level: 'critical',
        confidence: 0.85,
        auto_block: 1
      },
      {
        signature_id: 'SIG-ATTACK-XSS',
        name: 'Cross-Site Scripting Pattern',
        description: 'XSS attack patterns',
        signature_type: 'attack_pattern',
        pattern: '(<script|javascript:|onerror=|onload=|<iframe|eval\\(|alert\\()',
        match_type: 'regex_case_insensitive',
        threat_level: 'high',
        confidence: 0.8,
        auto_block: 1
      },
      {
        signature_id: 'SIG-ATTACK-PATH-TRAVERSAL',
        name: 'Path Traversal Pattern',
        description: 'Directory traversal attack patterns',
        signature_type: 'attack_pattern',
        pattern: '(\\.\\./|\\.\\.\\\\/|%2e%2e/|%252e%252e/)',
        match_type: 'regex_case_insensitive',
        threat_level: 'high',
        confidence: 0.9,
        auto_block: 1
      },
      {
        signature_id: 'SIG-ATTACK-COMMAND-INJECTION',
        name: 'Command Injection Pattern',
        description: 'OS command injection patterns',
        signature_type: 'attack_pattern',
        pattern: '(;\\s*(rm|cat|ls|wget|curl|bash|sh|cmd|powershell)|\\|\\s*(nc|netcat))',
        match_type: 'regex_case_insensitive',
        threat_level: 'critical',
        confidence: 0.95,
        auto_block: 1
      },
      // Behavioral signatures
      {
        signature_id: 'SIG-BEHAVIOR-BRUTE-FORCE',
        name: 'Brute Force Behavior',
        description: 'Rapid repeated authentication attempts',
        signature_type: 'behavior',
        pattern: 'failed_login_rate',
        match_type: 'custom',
        threat_level: 'critical',
        confidence: 0.9,
        auto_block: 1
      },
      {
        signature_id: 'SIG-BEHAVIOR-CREDENTIAL-STUFFING',
        name: 'Credential Stuffing Behavior',
        description: 'Multiple username attempts from single source',
        signature_type: 'behavior',
        pattern: 'unique_username_rate',
        match_type: 'custom',
        threat_level: 'high',
        confidence: 0.85,
        auto_block: 1
      },
      {
        signature_id: 'SIG-BEHAVIOR-PRIVILEGE-ESC',
        name: 'Privilege Escalation Behavior',
        description: 'Repeated unauthorized access attempts',
        signature_type: 'behavior',
        pattern: 'authorization_failure_rate',
        match_type: 'custom',
        threat_level: 'critical',
        confidence: 0.95,
        auto_block: 1
      },
      {
        signature_id: 'SIG-BEHAVIOR-DATA-EXFIL',
        name: 'Data Exfiltration Behavior',
        description: 'Unusual data download patterns',
        signature_type: 'behavior',
        pattern: 'download_volume_rate',
        match_type: 'custom',
        threat_level: 'high',
        confidence: 0.8,
        auto_block: 0
      }
    ];

    for (const signature of defaultSignatures) {
      await new Promise((resolve, reject) => {
        db.run(
          `INSERT OR IGNORE INTO risk_signatures 
           (signature_id, name, description, signature_type, pattern, match_type, threat_level, confidence, auto_block)
           VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
          [
            signature.signature_id,
            signature.name,
            signature.description,
            signature.signature_type,
            signature.pattern,
            signature.match_type,
            signature.threat_level,
            signature.confidence,
            signature.auto_block
          ],
          (err) => {
            if (err) reject(err);
            else resolve();
          }
        );
      });
    }

    logger.info(`[RiskSignatureManager] Created ${defaultSignatures.length} default signatures`);
  }

  /**
   * Load signatures from database into memory
   */
  async loadSignatures() {
    return new Promise((resolve, reject) => {
      db.all(
        `SELECT * FROM risk_signatures WHERE enabled = 1`,
        [],
        (err, rows) => {
          if (err) {
            reject(err);
          } else {
            this.signatures.clear();
            rows.forEach(row => {
              this.signatures.set(row.signature_id, row);
            });
            logger.info(`[RiskSignatureManager] Loaded ${rows.length} active signatures`);
            resolve();
          }
        }
      );
    });
  }

  /**
   * Match input against risk signatures
   * CWE-778: Logs all signature matches
   */
  async matchSignatures(input, signatureType, context = {}) {
    const matchingSignatures = Array.from(this.signatures.values()).filter(
      s => s.signature_type === signatureType
    );

    if (matchingSignatures.length === 0) {
      return { matched: false, signatures: [] };
    }

    const matches = [];

    for (const signature of matchingSignatures) {
      const matched = this.testPattern(input, signature.pattern, signature.match_type);

      if (matched) {
        matches.push({
          ...signature,
          matchedInput: input,
          context
        });

        // Log signature match (CWE-778)
        logAggregator.aggregate('risk_signature_manager', 'warn', 'security', 'Risk signature matched', {
          signatureId: signature.signature_id,
          signatureName: signature.name,
          signatureType,
          threatLevel: signature.threat_level,
          confidence: signature.confidence,
          autoBlock: signature.auto_block === 1,
          matchedInput: input.substring(0, 100), // Truncate for logging
          context
        });

        logger.warn(`[RiskSignatureManager] Signature matched: ${signature.name} (${signature.threat_level})`);
      }
    }

    return {
      matched: matches.length > 0,
      signatures: matches,
      highestThreat: matches.length > 0 ? this.getHighestThreatLevel(matches) : null,
      shouldAutoBlock: matches.some(m => m.auto_block === 1)
    };
  }

  /**
   * Test pattern against input
   */
  testPattern(input, pattern, matchType) {
    try {
      switch (matchType) {
        case 'regex':
          return new RegExp(pattern).test(input);
        case 'regex_case_insensitive':
          return new RegExp(pattern, 'i').test(input);
        case 'exact':
          return input === pattern;
        case 'contains':
          return input.includes(pattern);
        case 'custom':
          // Custom patterns handled by specific detection methods
          return false;
        default:
          return false;
      }
    } catch (error) {
      logger.error(`[RiskSignatureManager] Pattern test error: ${error.message}`);
      return false;
    }
  }

  /**
   * Get highest threat level from matches
   */
  getHighestThreatLevel(matches) {
    const threatLevels = { critical: 4, high: 3, medium: 2, low: 1 };
    let highest = 'low';
    let highestScore = 0;

    for (const match of matches) {
      const score = threatLevels[match.threat_level] || 0;
      if (score > highestScore) {
        highestScore = score;
        highest = match.threat_level;
      }
    }

    return highest;
  }

  /**
   * Get all signatures
   */
  async getSignatures(filters = {}) {
    const { signatureType, threatLevel, enabled, limit = 100 } = filters;

    let whereClause = [];
    let params = [];

    if (signatureType) {
      whereClause.push('signature_type = ?');
      params.push(signatureType);
    }

    if (threatLevel) {
      whereClause.push('threat_level = ?');
      params.push(threatLevel);
    }

    if (enabled !== undefined) {
      whereClause.push('enabled = ?');
      params.push(enabled ? 1 : 0);
    }

    const where = whereClause.length > 0 ? `WHERE ${whereClause.join(' AND ')}` : '';
    params.push(limit);

    return new Promise((resolve, reject) => {
      db.all(
        `SELECT * FROM risk_signatures ${where}
         ORDER BY threat_level DESC, confidence DESC
         LIMIT ?`,
        params,
        (err, rows) => {
          if (err) reject(err);
          else resolve(rows);
        }
      );
    });
  }

  /**
   * Get signature by ID
   */
  async getSignatureById(signatureId) {
    return new Promise((resolve, reject) => {
      db.get(
        `SELECT * FROM risk_signatures WHERE signature_id = ?`,
        [signatureId],
        (err, row) => {
          if (err) reject(err);
          else resolve(row);
        }
      );
    });
  }

  /**
   * Create new signature
   * CWE-778: Logs signature creation
   */
  async createSignature(data, userId) {
    const signatureId = `SIG-${Date.now()}-${Math.random().toString(36).substr(2, 9).toUpperCase()}`;

    return new Promise((resolve, reject) => {
      db.run(
        `INSERT INTO risk_signatures 
         (signature_id, name, description, signature_type, pattern, match_type, threat_level, confidence, enabled, auto_block)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          signatureId,
          data.name,
          data.description || '',
          data.signature_type,
          data.pattern,
          data.match_type,
          data.threat_level,
          data.confidence || 0.8,
          data.enabled !== undefined ? (data.enabled ? 1 : 0) : 1,
          data.auto_block !== undefined ? (data.auto_block ? 1 : 0) : 0
        ],
        async (err) => {
          if (err) {
            reject(err);
          } else {
            await this.loadSignatures();

            // Log signature creation (CWE-778)
            logAggregator.aggregate('risk_signature_manager', 'info', 'security', 'Risk signature created', {
              signatureId,
              userId,
              name: data.name,
              signatureType: data.signature_type,
              threatLevel: data.threat_level,
              autoBlock: data.auto_block === 1
            });

            logger.info(`[RiskSignatureManager] Signature created: ${signatureId} by user ${userId}`);
            resolve({ signatureId });
          }
        }
      );
    });
  }

  /**
   * Update signature
   * CWE-778: Logs signature modifications
   */
  async updateSignature(signatureId, updates, userId) {
    const allowedFields = ['name', 'description', 'pattern', 'match_type', 'threat_level', 'confidence', 'enabled', 'auto_block'];
    const setClause = [];
    const params = [];

    for (const [key, value] of Object.entries(updates)) {
      if (allowedFields.includes(key)) {
        setClause.push(`${key} = ?`);
        params.push((key === 'enabled' || key === 'auto_block') ? (value ? 1 : 0) : value);
      }
    }

    if (setClause.length === 0) {
      throw new Error('No valid fields to update');
    }

    setClause.push('updated_at = CURRENT_TIMESTAMP');
    params.push(signatureId);

    return new Promise((resolve, reject) => {
      db.run(
        `UPDATE risk_signatures 
         SET ${setClause.join(', ')}
         WHERE signature_id = ?`,
        params,
        async (err) => {
          if (err) {
            reject(err);
          } else {
            await this.loadSignatures();

            // Log signature update (CWE-778)
            logAggregator.aggregate('risk_signature_manager', 'info', 'security', 'Risk signature updated', {
              signatureId,
              userId,
              updates
            });

            logger.info(`[RiskSignatureManager] Signature updated: ${signatureId} by user ${userId}`);
            resolve({ success: true });
          }
        }
      );
    });
  }

  /**
   * Delete signature
   * CWE-778: Logs signature deletion
   */
  async deleteSignature(signatureId, userId) {
    return new Promise((resolve, reject) => {
      db.run(
        `DELETE FROM risk_signatures WHERE signature_id = ?`,
        [signatureId],
        async (err) => {
          if (err) {
            reject(err);
          } else {
            await this.loadSignatures();

            // Log signature deletion (CWE-778)
            logAggregator.aggregate('risk_signature_manager', 'warn', 'security', 'Risk signature deleted', {
              signatureId,
              userId
            });

            logger.info(`[RiskSignatureManager] Signature deleted: ${signatureId} by user ${userId}`);
            resolve({ success: true });
          }
        }
      );
    });
  }

  /**
   * Get signature statistics
   */
  async getStatistics() {
    return new Promise((resolve, reject) => {
      db.get(
        `SELECT 
           COUNT(*) as total,
           SUM(CASE WHEN enabled = 1 THEN 1 ELSE 0 END) as enabled,
           SUM(CASE WHEN enabled = 0 THEN 1 ELSE 0 END) as disabled,
           SUM(CASE WHEN auto_block = 1 THEN 1 ELSE 0 END) as auto_block_enabled,
           COUNT(DISTINCT signature_type) as unique_types,
           COUNT(DISTINCT threat_level) as unique_threat_levels
         FROM risk_signatures`,
        [],
        (err, row) => {
          if (err) reject(err);
          else resolve(row);
        }
      );
    });
  }
}

// Create singleton instance
const riskSignatureManager = new RiskSignatureManager();

module.exports = riskSignatureManager;
