const { getPlaybookVersion, gradeV2Investigation, validateV2Playbook } = require('./playbookGrader');

const generateMockAlerts = (count, sourcesFilter = []) => {
    const sampleTitles = [
        "Brute Force Attack Detected",
        "Suspicious PowerShell Activity",
        "Malware Communication Blocked",
        "Data Exfiltration Attempt",
        "New Admin User Created",
        "Phishing Email Reported"
    ];
    const severities = ["Low", "Medium", "High", "Critical"];
    const allSources = ["Firewall", "EDR", "SIEM", "Email Gateway", "IDS/IPS", "Splunk", "CrowdStrike", "Wazuh", "Darktrace", "ExtraHop", "Azure Sentinel", "AWS GuardDuty", "Palo Alto Cortex", "SentinelOne", "Carbon Black", "NGFW", "DLP", "DNS Security", "Proofpoint", "Zscaler", "Syslog", "Linux Server"];

    // Use provided sources or default to all
    const activeSources = (sourcesFilter && sourcesFilter.length > 0) ? sourcesFilter : allSources;

    const alerts = [];

    for (let i = 0; i < count; i++) {
        const title = sampleTitles[Math.floor(Math.random() * sampleTitles.length)];
        const severity = severities[Math.floor(Math.random() * severities.length)];
        const source = activeSources[Math.floor(Math.random() * activeSources.length)];

        alerts.push({
            title: title,
            severity: severity,
            source: source,
            details: "Automatically generated alert details for " + title + ".\nTimestamp: " + new Date().toISOString() + "\n\nReal World Example: Similar to recent attacks on Sector 7.",
            alert_type: "Simulated Attack",
            mitre_technique: "T1000",
            real_world_example: 1,
            raw_log: {
                "timestamp": new Date().toISOString(),
                "src_ip": "192.168.1.100",
                "action": "Blocked",
                "file_name": "suspicious.exe"
            },
            playbook_solution: {
                playbook_version: 2,
                artifacts: [
                    {
                        id: "art_1",
                        type: "ip",
                        value: "192.168.1.100",
                        is_critical: true,
                        osint_result: {
                            source: "InternalDB",
                            verdict: "internal",
                            details: "Internal Host"
                        }
                    }
                ],
                expected_actions: ["close_alert"],
                expected_verdict: "false_positive",
                expected_category: "simulation",
                analysis_notes: "This is a simulated mock alert."
            }
        });
    }
    return alerts;
};

/**
 * Validate and fix alert artifacts to ensure consistency with raw_log.
 * This runs after AI generation to catch any mismatches.
 * Returns { validAlerts: [], invalidAlerts: [] }
 */
const validateAndFixAlerts = (alerts) => {
    if (!alerts || !Array.isArray(alerts)) return { validAlerts: [], invalidAlerts: [] };

    const validAlerts = [];
    const invalidAlerts = [];

    alerts.forEach((alert, index) => {
        // Parse JSON strings if needed
        if (typeof alert.playbook_solution === 'string') {
            try { alert.playbook_solution = JSON.parse(alert.playbook_solution); } catch (e) { }
        }
        if (typeof alert.raw_log === 'string') {
            try { alert.raw_log = JSON.parse(alert.raw_log); } catch (e) { }
        }

        const pb = alert.playbook_solution;
        const raw = alert.raw_log;

        if (!pb || !raw || !pb.artifacts) {
            console.log(`[Validate] Alert ${index}: No playbook or raw_log, skipping.`);
            validAlerts.push(alert);
            return;
        }

        // Collect all values from raw_log for matching
        const rawLogStr = JSON.stringify(raw).toLowerCase();
        const rawValues = extractValuesFromRawLog(raw);

        let fixed = false;
        let unfixable = false;

        // Validate each artifact
        const fixedArtifacts = [];

        pb.artifacts.forEach(artifact => {
            if (!artifact.value) return;

            const valueInRawLog = rawLogStr.includes(artifact.value.toLowerCase());

            if (!valueInRawLog) {
                console.log(`[Validate] Alert "${alert.title}": Artifact "${artifact.value}" NOT in raw_log`);

                // Try to auto-fix based on artifact type
                const fixedValue = findMatchingRawValue(artifact.type, rawValues);

                if (fixedValue) {
                    console.log(`[AutoFix] Replacing "${artifact.value}" with "${fixedValue}" from raw_log`);
                    artifact.value = fixedValue;
                    
                    // Update OSINT result if it's now an internal IP
                    if (artifact.type === 'ip' && isPrivateIP(fixedValue)) {
                        artifact.osint_result = {
                            source: "Internal Network",
                            verdict: "internal",
                            details: `Private IP address (${fixedValue}) from internal network range.`
                        };
                    }
                    fixed = true;
                    fixedArtifacts.push(artifact);
                } else {
                    console.warn(`[Validate] Alert "${alert.title}": Could not fix artifact type "${artifact.type}" - REMOVING`);
                    fixed = true; // Mark as modified
                }
            } else {
                fixedArtifacts.push(artifact);
            }
        });

        // Ensure every artifact has an osint_result (pro-active enrichment)
        const verdict = (pb.expected_verdict || pb.verdict || '').toLowerCase();
        
        fixedArtifacts.forEach(artifact => {
            if (!artifact.osint_result) {
                console.log(`[Enrich] Alert "${alert.title}": Adding missing osint_result for ${artifact.value}`);
                
                let defaultVerdict = 'clean';
                let details = 'No significant reputation data found.';

                if (artifact.type === 'ip' && isPrivateIP(artifact.value)) {
                    defaultVerdict = 'internal';
                    details = 'Internal private IP address.';
                } else if (artifact.is_critical && (verdict.includes('true') || verdict === 'malicious')) {
                    defaultVerdict = 'malicious';
                    details = 'Associated with malicious activity in this investigation.';
                } else if (verdict.includes('false') || verdict === 'benign') {
                    defaultVerdict = 'clean';
                    details = 'No malicious associations found for this indicator.';
                }

                artifact.osint_result = {
                    source: "Reputation Engine",
                    verdict: defaultVerdict,
                    details: details,
                    confidence: 85
                };
            }
        });

        pb.artifacts = fixedArtifacts;

        if (fixed) {
            console.log(`[Validate] Alert "${alert.title}": Auto-fixed artifacts.`);
        }

        if (unfixable) {
            invalidAlerts.push(alert);
        } else {
            validAlerts.push(alert);
        }
    });

    console.log(`[Validate] Results: ${validAlerts.length} valid, ${invalidAlerts.length} invalid/unfixable`);
    return { validAlerts, invalidAlerts };
};

/**
 * Extract common values from raw_log for matching
 */
const extractValuesFromRawLog = (raw) => {
    const values = {
        ips: [],
        domains: [],
        urls: [],
        emails: [],
        hashes: [],
        usernames: [],
        filenames: [],
        payloads: [],
        commands: []
    };

    const ipFields = ['src_ip', 'source_ip', 'dst_ip', 'destination_ip', 'ip', 'remote_ip', 'local_ip', 'attacker_ip', 'c2_ip', 'client_ip'];
    const domainFields = ['domain', 'host', 'hostname', 'fqdn', 'sender_domain', 'target_domain'];
    const urlFields = ['url', 'link', 'uri', 'payload_url', 'c2_url', 'requested_url'];
    const emailFields = ['email', 'sender', 'sender_email', 'recipient', 'from', 'to'];
    const hashFields = ['hash', 'file_hash', 'md5', 'sha1', 'sha256'];
    const userFields = ['username', 'user', 'account', 'target_user'];
    const fileFields = ['file_name', 'filename', 'file_path', 'process_name', 'executable'];
    const payloadFields = ['request_body', 'payload', 'body', 'query_string', 'parameters', 'input', 'data'];
    const commandFields = ['command_line', 'command', 'cmd', 'process_command', 'executed_command'];

    const extractField = (obj, fields, target) => {
        fields.forEach(field => {
            if (obj[field]) target.push(obj[field]);
        });
    };

    extractField(raw, ipFields, values.ips);
    extractField(raw, domainFields, values.domains);
    extractField(raw, urlFields, values.urls);
    extractField(raw, emailFields, values.emails);
    extractField(raw, hashFields, values.hashes);
    extractField(raw, userFields, values.usernames);
    extractField(raw, fileFields, values.filenames);
    extractField(raw, payloadFields, values.payloads);
    extractField(raw, commandFields, values.commands);

    // Also check entire raw_log string for attack patterns
    const rawStr = JSON.stringify(raw);
    
    // SQL injection patterns
    const sqlPatterns = [
        /' OR '/i, /' AND '/i, /--\s*$/m, /UNION\s+SELECT/i,
        /'\s*=\s*'/i, /1\s*=\s*1/i, /DROP\s+TABLE/i
    ];
    
    // XSS patterns
    const xssPatterns = [
        /<script/i, /javascript:/i, /onerror\s*=/i, /onload\s*=/i,
        /eval\s*\(/i, /document\.cookie/i
    ];
    
    // Command injection patterns (basic shell)
    const cmdPatterns = [
        /\$\(/, /`[^`]+`/, /;\s*\w+/, /\|\s*\w+/, /&&\s*\w+/
    ];
    
    // PowerShell patterns (critical for SOC training)
    const powershellPatterns = [
        /powershell/i, /pwsh/i,
        /-enc\s+[A-Za-z0-9+\/=]+/i,           // Encoded command
        /-encodedcommand\s+[A-Za-z0-9+\/=]+/i,
        /Invoke-Expression/i, /IEX\s*\(/i,   // Common obfuscation
        /Invoke-WebRequest/i, /IWR\s/i,      // Download cradle
        /Invoke-Mimikatz/i,                   // Credential theft
        /DownloadString\s*\(/i,               // .NET download
        /\[System\.Convert\]::FromBase64/i,  // Base64 decode
        /New-Object.*Net\.WebClient/i,       // Download
        /-nop\s+-w\s+hidden/i,               // Hidden window
        /bypass\s+-/i,                        // Execution bypass
        /Set-ExecutionPolicy/i
    ];
    
    // LOLBins (Living Off the Land Binaries)
    const lolbinPatterns = [
        /certutil.*-urlcache/i,               // Download via certutil
        /certutil.*-decode/i,                 // Decode via certutil
        /mshta\s+/i,                          // HTA execution
        /regsvr32.*\/s.*\/u.*\/i/i,          // Regsvr32 proxy
        /rundll32.*javascript/i,              // Rundll32 abuse
        /wmic.*process.*call.*create/i,       // WMIC process create
        /bitsadmin.*\/transfer/i,             // BITS download
        /cscript.*\/e:jscript/i,              // Script host
        /wscript.*\/e:jscript/i
    ];

    // If we find an attack pattern in the raw log, try to extract the payload
    const checkPatterns = (patterns, type) => {
        patterns.forEach(pattern => {
            if (pattern.test(rawStr)) {
                // Try to find the containing field value
                Object.entries(raw).forEach(([key, val]) => {
                    if (typeof val === 'string' && pattern.test(val)) {
                        if (type === 'sql' || type === 'xss') {
                            if (!values.payloads.includes(val)) values.payloads.push(val);
                        } else if (type === 'cmd') {
                            if (!values.commands.includes(val)) values.commands.push(val);
                        }
                    }
                });
            }
        });
    };

    checkPatterns(sqlPatterns, 'sql');
    checkPatterns(xssPatterns, 'xss');
    checkPatterns(cmdPatterns, 'cmd');
    checkPatterns(powershellPatterns, 'cmd');  // PowerShell goes to commands
    checkPatterns(lolbinPatterns, 'cmd');      // LOLBins go to commands

    return values;
};

/**
 * Find a matching value from raw_log based on artifact type
 */
const findMatchingRawValue = (type, rawValues) => {
    switch (type) {
        case 'ip':
            return rawValues.ips[0] || null;
        case 'domain':
        case 'hostname':
            return rawValues.domains[0] || null;
        case 'url':
            return rawValues.urls[0] || null;
        case 'email':
            return rawValues.emails[0] || null;
        case 'hash':
        case 'file_hash':
            return rawValues.hashes[0] || null;
        case 'username':
            return rawValues.usernames[0] || null;
        case 'filename':
        case 'file':
            return rawValues.filenames[0] || null;
        case 'payload':
        case 'request_body':
        case 'sql':
        case 'xss':
            return rawValues.payloads[0] || null;
        case 'command':
        case 'command_line':
        case 'cmd':
            return rawValues.commands[0] || null;
        default:
            return null;
    }
};

/**
 * Check if an IP is private/internal
 */
const isPrivateIP = (ip) => {
    if (!ip) return false;
    return /^10\./.test(ip) ||
           /^192\.168\./.test(ip) ||
           /^172\.(1[6-9]|2[0-9]|3[01])\./.test(ip) ||
           /^127\./.test(ip);
};

// Legacy function - now wraps validateAndFixAlerts
const applyConsistencyRules = (alerts) => {
    const { validAlerts } = validateAndFixAlerts(alerts);
    return validAlerts;
};

/**
 * Generate v2 alerts with structured artifacts and OSINT results
 * Supports batching for large requests to prevent LLM truncation
 */
const generateV2AlertContent = async (count, apiKey, options = {}) => {
    // We split into batches of 5 to avoid LLM tokens limit for complex JSON output
    const BATCH_SIZE = 5;
    
    if (count <= BATCH_SIZE) {
        return _generateSingleBatchV2(count, apiKey, options);
    }

    console.log(`[Batching] Splitting ${count} alerts into chunks of ${BATCH_SIZE} for reliability.`);
    
    const batches = [];
    let remaining = count;

    // Calculate initial distribution goals
    const totalTpGoal = options.verdictDistribution?.true_positive !== undefined 
        ? options.verdictDistribution.true_positive 
        : Math.ceil(count * 0.6);
    
    let tpRemaining = totalTpGoal;

    while (remaining > 0) {
        const currentBatchSize = Math.min(remaining, BATCH_SIZE);
        let batchTp = Math.min(tpRemaining, Math.ceil(currentBatchSize * (totalTpGoal / count)));
        batchTp = Math.max(0, Math.min(batchTp, currentBatchSize));
        const batchFp = currentBatchSize - batchTp;

        batches.push({
            size: currentBatchSize,
            tp: batchTp,
            fp: batchFp
        });

        remaining -= currentBatchSize;
        tpRemaining -= batchTp;
    }

    console.log(`[Batching] Prepared ${batches.length} batches. Starting parallel generation...`);

    // Use a concurrency limit to avoid hitting rate limits or overwhelming the server
    const CONCURRENCY_LIMIT = 3;
    const allResults = [];
    
    for (let i = 0; i < batches.length; i += CONCURRENCY_LIMIT) {
        const currentChunk = batches.slice(i, i + CONCURRENCY_LIMIT);
        console.log(`[Batching] Processing chunk ${Math.floor(i/CONCURRENCY_LIMIT) + 1}/${Math.ceil(batches.length/CONCURRENCY_LIMIT)}...`);
        
        const promises = currentChunk.map(batch => {
            const batchOptions = {
                ...options,
                verdictDistribution: { true_positive: batch.tp, false_positive: batch.fp }
            };
            return _generateSingleBatchV2(batch.size, apiKey, batchOptions)
                .catch(err => {
                    console.error(`[Batching] Single batch failed: ${err.message}`);
                    return []; // Return empty array on failure to keep going
                });
        });

        const results = await Promise.all(promises);
        results.forEach(batchAlerts => allResults.push(...batchAlerts));
    }

    console.log(`[Batching] Total successfully generated: ${allResults.length}/${count}`);
    return allResults;
};

/**
 * Single batch generation logic (Internal)
 */
const _generateSingleBatchV2 = async (count, apiKey, options = {}) => {
    // Local provider might not need an API key
    const provider = options.provider || 'openai';
    
    if (!apiKey && provider !== 'local') {
        throw new Error("No API key provided for AI generation. Please configure it in Settings.");
    }

    const axios = require('axios');
    
    // Prepare prompt
    const difficulty = options.difficulty || 'Intermediate';
    let difficultyInstruction = "";
    
    // 5-Tier Difficulty System
    switch (difficulty) {
        case 'Novice':
            difficultyInstruction = `DIFFICULTY: NOVICE (Level 1-2)
- Very simple, obvious attacks (failed login brute force, clear malware signature)
- All malicious indicators should scream "RED FLAG"
- Single-stage attacks only
- External IPs always clearly malicious (from known bad countries/VPNs)
- File hashes with 50+ detection on VirusTotal
- No obfuscation, no LOLBins
- Perfect for first-day SOC analysts`;
            break;
        case 'Beginner':
            difficultyInstruction = `DIFFICULTY: BEGINNER (Level 3-4)
- Clear indicators but requires IOC extraction
- Basic MITRE techniques (T1059, T1078, T1566)
- Include 2-3 artifacts to analyze
- Malicious verdicts obvious after OSINT lookup
- May include one false positive for practice
- No encoding or obfuscation`;
            break;
        case 'Intermediate':
            difficultyInstruction = `DIFFICULTY: INTERMEDIATE (Level 5-6)
- Mix of obvious and subtle indicators
- MITRE technique chains (Initial Access → Execution → Persistence)
- Include both true positives and false positives (60/40 ratio)
- Some internal IP traffic that needs context
- Basic encoding (Base64) but decoded values still clear
- Requires correlating multiple log fields`;
            break;
        case 'Advanced':
            difficultyInstruction = `DIFFICULTY: ADVANCED (Level 7-8)
- Multi-stage attacks with lateral movement
- Use LOLBins (certutil, mshta, regsvr32)
- PowerShell with -enc encoded commands
- Living-off-the-land techniques
- False positives that look very suspicious
- Require threat hunting mindset
- Internal-to-internal traffic patterns
- Timestamp correlation required`;
            break;
        case 'Expert':
            difficultyInstruction = `DIFFICULTY: EXPERT (Level 9-10)
- APT-level sophistication (nation-state TTPs)
- Heavy obfuscation, fileless malware
- Multi-hop C2 through legitimate services (Slack, Discord, GitHub)
- DGA domains, fast-flux DNS
- Memory-only payloads, process hollowing
- Subtle indicators buried in noise
- Defensive evasion (timestomping, log deletion)
- Require attribution analysis
- Include decoy/distraction artifacts`;
            break;
        default:
            difficultyInstruction = `DIFFICULTY: INTERMEDIATE (Level 5-6)
- Mix of obvious and subtle indicators
- Include both true positives and false positives`;
    }

    // Sector/Industry specific instructions
    let sectorInstruction = "";
    const sectorCode = options.sector_code || 'auto';
    if (sectorCode && sectorCode !== 'auto') {
        const sectorDetails = {
            'HEALTHCARE': `INDUSTRY: HEALTHCARE
- Include HIPAA-relevant scenarios (PHI exposure, unauthorized ePHI access)
- Medical device compromise, EHR system attacks
- Targets: Hospitals, clinics, health insurance
- Data types: Patient records, SSN, medical history
- Compliance context: HIPAA, HITECH`,
            'FINANCE': `INDUSTRY: FINANCE
- Include PCI-DSS, SOX scenarios
- SWIFT network attacks, trading fraud, card skimming
- Targets: Banks, trading firms, insurance, payment processors
- Data types: Credit cards, account numbers, transaction data
- Compliance context: PCI-DSS, SOX, GLBA`,
            'GOVERNMENT': `INDUSTRY: GOVERNMENT
- Nation-state actor TTPs, APT campaigns
- Classified data exfiltration, espionage scenarios
- Targets: Federal agencies, defense contractors, election systems
- Data types: CUI, classified docs, personnel records
- Compliance context: FISMA, FedRAMP, NIST 800-53`,
            'OT_ICS': `INDUSTRY: OT/ICS (Industrial Control Systems)
- SCADA attacks, PLC manipulation, HMI compromise
- Modbus/DNP3 protocol anomalies
- Targets: Power plants, water treatment, manufacturing
- Threats: Triton, Industroyer, Stuxnet-style
- Safety implications: Physical process disruption`,
            'RETAIL': `INDUSTRY: RETAIL
- POS malware, e-commerce fraud, card skimming
- Supply chain attacks, loyalty program abuse
- Targets: Online stores, brick-and-mortar, distribution
- Data types: Payment cards, customer PII
- Peak season: Black Friday, holiday attacks`,
            'ENERGY': `INDUSTRY: ENERGY
- Power grid attacks, oil/gas infrastructure
- Pipeline SCADA, smart meter manipulation
- Targets: Utilities, refineries, nuclear facilities
- APT groups: Sandworm, Dragonfly
- Critical infrastructure focus`,
            'TECH': `INDUSTRY: TECHNOLOGY
- Source code theft, CI/CD pipeline attacks
- API key exposure, cloud misconfiguration
- Targets: SaaS providers, dev teams, cloud infra
- Data types: IP, customer data, credentials
- Supply chain: npm/pypi poisoning`
        };
        sectorInstruction = sectorDetails[sectorCode] || '';
    }

    // Campaign Pack specific instructions
    let campaignInstruction = "";
    const campaignPack = options.campaign_pack || 'general';
    if (campaignPack && campaignPack !== 'general') {
        const campaignDetails = {
            'ransomware': `CAMPAIGN PACK: RANSOMWARE
Generate alerts simulating real ransomware operations:
- Actors: LockBit 3.0, BlackCat/ALPHV, Qilin, Akira, Royal, Play
- TTPs: Initial access via RDP/VPN, Cobalt Strike beacons, volume shadow deletion
- Indicators: .lockbit/.alphv extensions, ransom notes, double extortion
- Lateral movement with PsExec, WMI
- Pre-encryption reconnaissance and data staging`,
            'apt': `CAMPAIGN PACK: APT (Advanced Persistent Threats)
Generate alerts simulating nation-state operations:
- Actors: APT41 (China), Lazarus (DPRK), Cozy Bear/APT29 (Russia), Fancy Bear/APT28
- TTPs: Spear-phishing, supply chain, zero-days
- Long dwell time, stealthy exfil
- Use of legitimate services for C2 (GitHub, Slack)
- Custom malware, fileless techniques`,
            'phishing': `CAMPAIGN PACK: PHISHING
Generate alerts simulating email-based attacks:
- Types: BEC (Business Email Compromise), spear phishing, credential harvest
- Lures: Invoice fraud, CEO impersonation, Office365 login pages
- Indicators: Lookalike domains, urgency language, suspicious attachments
- OAuth phishing, QR code phishing
- Include email headers, sender analysis`,
            'cloud': `CAMPAIGN PACK: CLOUD ATTACKS
Generate alerts for cloud infrastructure attacks:
- Platforms: AWS, Azure, GCP
- Attacks: Exposed S3 buckets, IAM privilege escalation, Lambda abuse
- Indicators: GuardDuty alerts, Sentinel detections, CloudTrail anomalies
- Crypto mining, cloud resource hijacking
- Misconfigurations leading to data exposure`
        };
        campaignInstruction = campaignDetails[campaignPack] || '';
    }

    // Scenario Context (Custom Prompt from Admin)
    let scenarioInstruction = "";
    if (options.scenario_context && options.scenario_context.trim().length > 0) {
        scenarioInstruction = `SCENARIO CONTEXT (CRITICAL): ${options.scenario_context}
Generate alerts that specifically match this scenario description. Use this context to determine the attack vector, source, and indicators.`;
    }

    // Determine verdict distribution
    const verdictDist = options.verdictDistribution || { true_positive: Math.ceil(count * 0.6), false_positive: Math.floor(count * 0.4) };
    const tpCount = verdictDist.true_positive || 0;
    const fpCount = verdictDist.false_positive || 0;

    const currentDate = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
    const v2Prompt = `You are a SOC Training Platform generating realistic security alerts with investigation playbooks.

Generate ${count} unique cybersecurity alerts in v2 format.
- ${tpCount} should be TRUE POSITIVE (actual attacks)
- ${fpCount} should be FALSE POSITIVE (benign activity that looks suspicious)
${options.sources?.length ? `Use these security tools as sources: ${options.sources.join(', ')}` : 'Use varied security tools: EDR, SIEM, Firewall, Email Gateway, IDS/IPS, etc.'}
${difficultyInstruction}
${sectorInstruction ? '\n' + sectorInstruction : ''}
${campaignInstruction ? '\n' + campaignInstruction : ''}
${scenarioInstruction ? '\n' + scenarioInstruction : ''}

CRITICAL: Use the CURRENT DATE for all logs and timestamps. Today is ${currentDate}.
Timestamps should be recent (within the last 24 hours).

OUTPUT: Valid JSON with key "alerts" array. Each alert MUST have this EXACT structure:

{
  "title": "Alert title describing the security event",
  "severity": "Low|Medium|High|Critical",
  "source": "CrowdStrike|Splunk|Wazuh|Proofpoint|Firewall|etc",
  "details": "2-3 sentence description of what was detected",
  "alert_type": "Malware|Phishing|Brute Force|Lateral Movement|Data Exfil|etc",
  "mitre_technique": "T1XXX",
  "real_world_example": 0 or 1,
  "is_false_positive": true or false,
  "raw_log": {
    "timestamp": "ISO timestamp",
    "event_type": "login_failure|process_execution|network_connection|email_received|web_request|etc",
    "src_ip": "EXTERNAL IP for attacks or INTERNAL (192.168.x.x, 10.x.x.x) for victim machines",
    "dst_ip": "Target IP if applicable",
    "username": "Affected user account",
    "hostname": "Affected machine name",
    "request_body": "For web attacks: the malicious payload (SQL injection, XSS, etc.)",
    "command_line": "For process execution: the full command line"
    // Include other relevant fields: file_hash, domain, url, email_sender, etc.
    // ALL artifact values in playbook_solution MUST come from here
  },
  "sector_code": "HEALTHCARE|FINANCE|GOVERNMENT|OT_ICS|RETAIL|ENERGY|TECH (Select most relevant)",
  "playbook_solution": {
    "playbook_version": 2,
    "artifacts": [
      {
        "id": "artifact_1",
        "type": "ip|hash|domain|url|email|filename|username|payload|command",
        "value": "EXACT value copied from raw_log",
        "is_critical": true,
        "osint_result": {
          "source": "AbuseIPDB|VirusTotal|URLScan|Hybrid Analysis|Pattern Analysis|etc",
          "verdict": "malicious|suspicious|clean|internal",
          "details": "Realistic OSINT finding (e.g., 'IP reported 847 times for brute force attacks')"
        }
      }
      // Include 2-5 artifacts per alert. For web attacks, ALWAYS include the payload/request_body as an artifact.
    ],
    "expected_actions": ["block_ip", "isolate_host", "reset_credentials", "block_hash", "close_alert"],
    "expected_verdict": "true_positive OR false_positive",
    "expected_category": "malware|phishing|credential_attack|lateral_movement|data_exfiltration|web_attack",
    "analysis_notes": "Brief explanation of why this verdict is correct"
  }
}

CRITICAL RULES - FOLLOW EXACTLY:

1. **ARTIFACT CONSISTENCY**: Every artifact value MUST be copied EXACTLY from raw_log. Never invent values.
   - If raw_log has "src_ip": "203.0.113.45", artifact value must be "203.0.113.45"

2. **PRIVATE IP HANDLING**: 
   - Internal/victim IPs (192.168.x.x, 10.x.x.x, 172.16-31.x.x) should have verdict "internal" with details explaining it's an internal address
   - External attacker IPs should have verdict "malicious" or "suspicious"
   - NEVER mark private IPs as "malicious" in OSINT results

3. **OSINT CONSISTENCY**:
   - For TRUE POSITIVE: At least one artifact MUST have verdict "malicious", and "is_false_positive" must be false
   - For FALSE POSITIVE: All artifacts should be "clean" or "suspicious" (not malicious), and "is_false_positive" must be true
   - Internal IPs always get verdict "internal"

4. **EXPECTED ACTIONS**:
   - TRUE POSITIVE: Include actions like isolate_host, block_ip, reset_credentials, collect_forensics
   - FALSE POSITIVE: Only include "close_alert"

5. **REALISTIC SCENARIOS**:
   - Brute force: Show failed_attempts count (5-50), foreign IP, suspicious location
   - Phishing: Include sender email, malicious URL, spoofed domain
   - Malware: Include file hash, suspicious process, C2 IP
   - Lateral movement: Show internal IPs, PSExec/WMI activity
   - Web attacks: Include request_body with SQL injection/XSS payload, target URL, attacker IP
   - Command injection: Include the full malicious command_line

7. **PAYLOAD ARTIFACTS**: For SQL injection, XSS, command injection attacks:
   - The malicious payload MUST be included as an artifact with type "payload"
   - Example SQL: "' OR '1'='1' --" should be artifact with verdict "malicious", details "SQL injection attempt detected"
   - Example XSS: "<script>alert(1)</script>" should be artifact with type "payload"

6. **IS_CRITICAL MARKING**: Mark artifacts that are essential for investigation (attacker IP, malicious hash, phishing URL) as is_critical: true

Return ONLY valid JSON with the "alerts" array.`;

    try {
        console.log(`--- Generating ${count} v2 Playbook Alerts via ${provider.toUpperCase()} (${tpCount} TP, ${fpCount} FP) ---`);
        
        let alerts = [];

        if (provider === 'openai') {
            const headers = {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${apiKey}`
            };
            const response = await axios.post('https://api.openai.com/v1/chat/completions', {
                model: "gpt-4o",
                messages: [
                    { role: "system", content: "You are a cybersecurity training platform generating realistic alerts with investigation playbooks. Ensure perfect consistency between raw_log and playbook artifacts. Output valid JSON only." },
                    { role: "user", content: v2Prompt }
                ],
                response_format: { type: "json_object" },
                temperature: 0.7
            }, { headers, timeout: 120000 });

            const content = JSON.parse(response.data.choices[0].message.content);
            alerts = content.alerts || [];

        } else if (provider === 'anthropic') {
            // Anthropic (Claude)
            const anthropicHeaders = {
                'x-api-key': apiKey,
                'anthropic-version': '2023-06-01',
                'content-type': 'application/json'
            };

            const response = await axios.post('https://api.anthropic.com/v1/messages', {
                model: "claude-3-opus-20240229", // Or latest available
                max_tokens: 4096,
                system: "You are a cybersecurity training platform generating realistic alerts with investigation playbooks. Ensure perfect consistency between raw_log and playbook artifacts. Output valid JSON with the 'alerts' array only.",
                messages: [
                    { role: "user", content: v2Prompt }
                ],
                temperature: 0.7
            }, { headers: anthropicHeaders, timeout: 120000 });

            // Parse Anthropic Response
            // Anthropic returns content as array of blocks: [{ type: 'text', text: '...' }]
            const responseText = response.data.content[0].text;
            
            // Extract JSON if wrapped in text
            try {
                // Try to find the JSON block if the model was chatty
                const jsonMatch = responseText.match(/\{[\s\S]*\}/);
                const jsonStr = jsonMatch ? jsonMatch[0] : responseText;
                const content = JSON.parse(jsonStr);
                alerts = content.alerts || [];
            } catch (e) {
                console.error("Failed to parse Anthropic JSON response:", responseText.substring(0, 200));
                throw new Error("Invalid JSON response from Anthropic");
            }

        } else if (provider === 'local') {
            // Local LLM (Ollama)
            const response = await axios.post('http://localhost:11434/api/chat', {
                model: options.model || "llama3", // Default to llama3 or user preference if available
                messages: [
                    { role: "system", content: "You are a cybersecurity training platform. Output valid JSON only." },
                    { role: "user", content: v2Prompt }
                ],
                stream: false,
                format: "json", // Ollama supports strict JSON mode
                options: {
                    temperature: 0.7
                }
            }, { timeout: 120000 });

            try {
                const content = JSON.parse(response.data.message.content);
                alerts = content.alerts || [];
            } catch (e) {
                console.error("Failed to parse Local LLM JSON response:", response.data.message.content.substring(0, 200));
                throw new Error("Invalid JSON response from Local LLM");
            }
        } else {
            throw new Error(`Unsupported AI Provider: ${provider}`);
        }

        // Post-processing: Ensure playbook_version is set
        alerts.forEach(alert => {
            if (alert.playbook_solution) {
                alert.playbook_solution.playbook_version = 2;
            }
        });

        // STRICT VALIDATION: Auto-fix any artifact mismatches with raw_log
        const validation = validateAndFixAlerts(alerts);
        alerts = validation.validAlerts;

        if (validation.invalidAlerts.length > 0) {
            console.warn(`[v2 Generation] ${validation.invalidAlerts.length} alerts could not be fixed and were discarded.`);
        }

        console.log(`--- Successfully generated ${alerts.length} consistent v2 alerts ---`);
        return alerts;


    } catch (error) {
        console.error(`${provider.toUpperCase()} v2 Generation Error:`, error.message);
        if (error.response) console.error("Provider Response:", error.response.data);
        
        throw new Error(`AI Generation Failed (${provider}): ${error.message}`);
    }
};

const generateAlertContent = async (count, apiKey, provider, options = {}) => {
    // Options: { severityCounts, verdictDistribution, includeRawLogs, sources, useV2 }
    
    // FORCE V2 (Playbook) Generation
    // We have deprecated V1. All alerts must provide a playbook_solution.
    
    // Pass 'useV2: true' explicitly to be safe, though we are calling the V2 function directly below.
    const v2Options = { ...options, useV2: true, provider: provider };

    return generateV2AlertContent(count, apiKey, v2Options);
};

/**
 * Evaluate investigation - routes to v1 (AI) or v2 (objective) grading
 */
const evaluateInvestigation = async (ticketData, settings, alert = null) => {
    // Detect playbook version
    const version = alert ? getPlaybookVersion(alert) : 1;
    console.log(`[Grading] Playbook version detected: v${version}`);

    // --- V2 Objective Grading ---
    if (version === 2 && alert?.playbook_solution) {
        const playbook = typeof alert.playbook_solution === 'string'
            ? JSON.parse(alert.playbook_solution)
            : alert.playbook_solution;

        const submission = {
            checkedArtifacts: ticketData.checkedArtifacts || [],
            selectedActions: ticketData.selectedActions || [],
            verdict: ticketData.verdict,
            conclusion: ticketData.conclusion || ticketData.summary || ''
        };

        console.log("[Grading] Using objective v2 grading...");
        const result = gradeV2Investigation(submission, playbook);
        return result;
    }

    // --- V1 AI-Based Grading (Legacy) ---
    // --- V1 AI-Based Grading (Legacy) ---
    // DEPRECATED: We are removing the subjective AI grading ("Handler Echo").
    // If we reach here, it means we have a Version 1 alert (no playbook_solution).
    
    console.warn(`[Grading] Deprecated V1 alert detected (ID: ${alert?.id || 'unknown'}). Cannot grade objectively.`);

    return {
        grade: 100, // Pass by default for legacy alerts to avoid blocking users
        feedback: "Legacy investigation (V1) complete. Transitioning to Playbook System (V2).",
        ai_summary: {
            verdict_correctness: "N/A",
            key_findings: "Legacy Format",
            missed_items: [],
            strengths: "Completed"
        }
    };
};

/**
 * Generate SEO metadata for a blog post
 */
const generateBlogSeo = async (title, content, apiKey) => {
    if (!apiKey) {
        throw new Error("No API key provided for SEO generation");
    }

    const axios = require('axios');
    const headers = {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${apiKey}`
    };

    const prompt = `You are an SEO expert. Generate optimized SEO metadata for the following blog post.

Title: ${title}
Content Preview: ${content.substring(0, 3000)}...

OUTPUT: Valid JSON with these exact keys:
{
  "seo_title": "Optimized title (max 60 chars)",
  "seo_description": "Meta description (max 160 chars, compelling)",
  "focus_keyword": "Primary keyword phrase (1-3 words)",
  "image_alt": "Descriptive alt text for featured image (max 125 chars, describe what the image would show based on the article topic)"
}
`;

    try {
        const response = await axios.post('https://api.openai.com/v1/chat/completions', {
            model: "gpt-4o",
            messages: [
                { role: "system", content: "You are an SEO expert. Output valid JSON only." },
                { role: "user", content: prompt }
            ],
            response_format: { type: "json_object" },
            temperature: 0.7
        }, { headers, timeout: 60000 });

        return JSON.parse(response.data.choices[0].message.content);
    } catch (error) {
        console.error("OpenAI SEO Generation Error:", error.message);
        throw new Error("Failed to generate SEO metadata");
    }
};



/**
 * Generate catchy blog titles
 */
const generateBlogTitle = async (content, apiKey) => {
    if (!apiKey) throw new Error("No API key");
    const axios = require('axios');
    const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` };

    const prompt = `Generate 5 catchy, professional, and SEO-friendly blog titles for this content.
    Content Preview: ${content.substring(0, 1000)}...
    
    OUTPUT: Valid JSON format: { "titles": ["Title 1", "Title 2", ...] }`;

    try {
        const response = await axios.post('https://api.openai.com/v1/chat/completions', {
            model: "gpt-4o",
            messages: [{ role: "system", content: "You are a professional blog editor. Output JSON only." }, { role: "user", content: prompt }],
            response_format: { type: "json_object" },
            temperature: 0.8
        }, { headers, timeout: 30000 });
        return JSON.parse(response.data.choices[0].message.content).titles;
    } catch (error) {
        console.error("AI Title Error:", error.message);
        throw new Error("Failed to generate titles");
    }
};

/**
 * Enhance/Format blog content
 */
const enhanceBlogContent = async (content, apiKey) => {
    if (!apiKey) throw new Error("No API key");
    const axios = require('axios');
    const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` };

    const prompt = `You are an expert editor. Improve the following blog post content.
    TASKS:
    1. Fix grammar and spelling.
    2. Structure with proper Markdown headings (H1, H2, H3).
    3. Improve readability and flow.
    4. Keep the same meaning and tone.
    5. Ensure code blocks are properly formatted if any.

    CONTENT:
    ${content.substring(0, 15000)}

    OUTPUT: just the enhanced Markdown content. NO JSON. NO conversational filler.`;

    try {
        const response = await axios.post('https://api.openai.com/v1/chat/completions', {
            model: "gpt-4o",
            messages: [{ role: "system", content: "You are an expert editor. Output only valid Markdown." }, { role: "user", content: prompt }],
            temperature: 0.7
        }, { headers, timeout: 90000 });
        return response.data.choices[0].message.content;
    } catch (error) {
        console.error("AI Enhance Error:", error.message);
        throw new Error("Failed to format content");
    }
};

/**
 * Generate Alert from News
 * Transforms a news item into a playable platform alert (v2 format)
 */
const generateAlertFromNews = async (newsItem, apiKey, provider = 'openai', options = {}) => {
    if (!apiKey && provider !== 'local') {
        throw new Error("No API key provided for AI generation.");
    }

    const axios = require('axios');
    const difficultyMapping = {
        1: 'Novice', 2: 'Novice',
        3: 'Beginner', 4: 'Beginner',
        5: 'Intermediate', 6: 'Intermediate',
        7: 'Advanced', 8: 'Advanced',
        9: 'Expert', 10: 'Expert'
    };
    const difficultyLabel = difficultyMapping[options.level] || 'Intermediate';
    
    const prompt = `You are a SOC Training Platform generating realistic security alerts with investigation playbooks.
    
    BASE NEWS ARTICLE:
    Title: ${newsItem.title}
    Content: ${newsItem.fullContent || newsItem.contentSnippet || newsItem.content}
    
    TASK:
    Transform this real-world news event into ONE (1) playable cybersecurity alert in v2 format for our SOC simulator.
    The alert must be technically consistent with the news but adapted to look like a detection from a specific security tool (EDR, SIEM, Firewall, etc.).
    
    CRITICAL: Use the CURRENT DATE for all logs and timestamps. Today is ${new Date().toISOString().split('T')[0]}.
    
    ${options.path_code && options.path_code !== 'AUTO' ? `FORCE CAREER PATH: ${options.path_code}` : 'SUGGEST CAREER PATH: Detect the most relevant path (SIEM, EDR, NDR, TI, IR, MAL, DLP, CLOUD).'}
    FORCE DIFFICULTY: ${difficultyLabel} (Level: ${options.level || 5})
    
    OUTPUT: Valid JSON for a single alert with this EXACT structure:
    {
      "title": "Alert title based on news",
      "severity": "Low|Medium|High|Critical",
      "source": "CrowdStrike|Splunk|Wazuh|Proofpoint|Firewall|etc",
      "details": "Technical summary explaining the detection based on the news story",
      "alert_type": "Malware|Phishing|Ransomware|Exploit|etc",
      "mitre_technique": "T1XXX",
      "real_world_example": 1,
      "is_false_positive": false,
      "difficulty": "Novice|Beginner|Intermediate|Advanced|Expert",
      "min_level": ${options.level || 5},
      "path_code": "SIEM|EDR|NDR|TI|IR|MAL|DLP|CLOUD",
      "sector_code": "HEALTHCARE|FINANCE|GOVERNMENT|OT_ICS|RETAIL|ENERGY|TECH",
      "raw_log": {
        "timestamp": "ISO timestamp",
        "event_type": "process_execution|network_connection|cloud_api_call|http_request|email_delivery|etc",
        "src_ip": "Attacker or Victim IP",
        "dst_ip": "Target IP",
        "user_agent": "Include for web/cloud attacks",
        "command_line": "Include full command for host-based attacks (e.g., powershell -enc ...)",
        "file_hash": "Include if malware/dropper",
        "request_url": "Include for web attacks",
        "request_body": "Include payloads (SQLi, XSS) if applicable",
        "additional_context": "MUST include deeply detailed, realistic fields matching the news (e.g., CloudTrail resource ARNs, Windows Event IDs, registry keys, precise error codes). Make it look like a real SIEM output!"
      },
      "playbook_solution": {
        "playbook_version": 2,
        "artifacts": [
          {
            "id": "art_1",
            "type": "ip|hash|domain|url|filename|command",
            "value": "Value from raw_log",
            "is_critical": true,
            "osint_result": { "source": "OSINT", "verdict": "malicious|suspicious|clean|internal", "details": "Context from news" }
          }
        ],
        "expected_actions": ["block_ip", "isolate_host", "close_alert"],
        "expected_verdict": "true_positive",
        "expected_category": "malware|phishing|exploit|etc",
        "analysis_notes": "Technical explanation"
      }
    }
    
    STRICT RULES:
    1. ARTIFACT CONSISTENCY: Every artifact value MUST be copied EXACTLY from raw_log.
    2. V2 FORMAT: You MUST include the playbook_solution with structured artifacts.
    3. DIFFICULTY: Ensure the artifacts and narrative match the forced difficulty level.
    4. PATH: If path is forced, use it. If not, pick the best fit from the list.
    5. RAW LOG REALISM (CRITICAL): Do NOT generate short logs. The "raw_log" object must be highly detailed and realistic, mimicking real outputs from CloudTrail, Sysmon, Zeek, or WAF depending on the attack type. Include irrelevant noise fields alongside the malicious indicators just like a real log.
    
    Return ONLY valid JSON.`;

    try {
        let alert = null;

        if (provider === 'openai') {
            const response = await axios.post('https://api.openai.com/v1/chat/completions', {
                model: "gpt-4o",
                messages: [
                    { role: "system", content: "You are a cybersecurity training platform. Output valid JSON only." },
                    { role: "user", content: prompt }
                ],
                response_format: { type: "json_object" },
                temperature: 0.7
            }, { 
                headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
                timeout: 60000 
            });

            alert = JSON.parse(response.data.choices[0].message.content);
        } else if (provider === 'mock') {
            console.log('[AI Mock] Generating mock alert for news:', newsItem.title);
            alert = {
                title: `[MOCK] ${newsItem.title}`,
                severity: "Medium",
                source: "ThreatIntel Mock",
                details: `Mocked investigation for: ${newsItem.title}`,
                alert_type: "Malware",
                mitre_technique: "T1059",
                real_world_example: 1,
                is_false_positive: false,
                difficulty: difficultyLabel,
                min_level: options.level || 5,
                path_code: options.path_code === 'AUTO' ? 'MAL' : options.path_code,
                sector_code: "FINANCE",
                raw_log: {
                    timestamp: new Date().toISOString(),
                    event_type: "mock_event",
                    src_ip: "1.2.3.4",
                    dst_ip: "8.8.8.8",
                    process_name: "malicious.exe"
                },
                playbook_solution: {
                    playbook_version: 2,
                    artifacts: [
                        {
                            id: "art_1",
                            type: "ip",
                            value: "1.2.3.4",
                            is_critical: true,
                            osint_result: {
                                source: "Mock OSINT",
                                verdict: "malicious",
                                details: "Confirmed malicious in mock database."
                            }
                        }
                    ],
                    expected_actions: ["block_ip", "close_alert"],
                    expected_verdict: "true_positive",
                    expected_category: "malware",
                    analysis_notes: "This is a mock analysis for verification."
                }
            };
        } else {
            // Add other providers if needed, otherwise fallback or error
            throw new Error(`Provider ${provider} not supported for individual news-to-alert conversion yet.`);
        }

        if (alert) {
            alert.playbook_solution.playbook_version = 2;
            const { validateAndFixAlerts } = require('./aiService'); // Use self-reference for utility if needed or import
            
            // Validate the single alert
            const validation = validateAndFixAlerts([alert]);
            return validation.validAlerts.length > 0 ? validation.validAlerts[0] : null;
        }

        return null;
    } catch (error) {
        console.error("generateAlertFromNews Error:", error.message);
        throw error;
    }
};

module.exports = {
    generateAlertContent,
    generateV2AlertContent,
    generateMockAlerts,
    evaluateInvestigation,
    getPlaybookVersion,
    validateAndFixAlerts,
    generateBlogSeo,
    generateBlogTitle,
    enhanceBlogContent,
    generateAlertFromNews
};
