<?php

declare(strict_types=1);

/**
 * ML Adapter Integration Tests
 *
 * Tests all 3 ML adapters with ModelRegistry and ModelPerformanceMonitor:
 * 1. QueueAnomalyModelAdapter
 * 2. WafBehavioralModelAdapter
 * 3. NPlusOneModelAdapter
 */

require_once __DIR__ . '/../../vendor/autoload.php';

use App\Framework\Queue\MachineLearning\QueueAnomalyModelAdapter;
use App\Framework\Queue\MachineLearning\JobAnomalyDetector;
use App\Framework\Queue\MachineLearning\ValueObjects\JobFeatures;
use App\Framework\Waf\MachineLearning\WafBehavioralModelAdapter;
use App\Framework\Waf\MachineLearning\BehaviorAnomalyDetector;
use App\Framework\Waf\MachineLearning\ValueObjects\BehaviorFeatures;
use App\Framework\Database\NPlusOneDetection\MachineLearning\NPlusOneModelAdapter;
use App\Framework\Database\NPlusOneDetection\MachineLearning\NPlusOneDetectionEngine;
use App\Framework\MachineLearning\ModelManagement\InMemoryModelRegistry;
use App\Framework\MachineLearning\ModelManagement\ModelPerformanceMonitor;
use App\Framework\MachineLearning\ModelManagement\InMemoryPerformanceStorage;
use App\Framework\MachineLearning\ModelManagement\NullAlertingService;
use App\Framework\Core\ValueObjects\Score;

echo "=== ML Adapter Integration Tests ===\n\n";

try {
    // Initialize shared infrastructure
    echo "1. Initializing Model Management Infrastructure...\n";
    $registry = new InMemoryModelRegistry();
    $storage = new InMemoryPerformanceStorage();
    $alerting = new NullAlertingService();
    $performanceMonitor = new ModelPerformanceMonitor($registry, $storage, $alerting);
    echo "   ✓ ModelRegistry created\n";
    echo "   ✓ PerformanceStorage created\n";
    echo "   ✓ ModelPerformanceMonitor created\n\n";

    // ========================================================================
    // Test 1: QueueAnomalyModelAdapter
    // ========================================================================
    echo "2. Testing QueueAnomalyModelAdapter...\n";

    // Create detector and adapter
    $queueDetector = new JobAnomalyDetector(
        anomalyThreshold: new Score(0.4),
        zScoreThreshold: 3.0,
        iqrMultiplier: 1.5
    );
    $queueAdapter = new QueueAnomalyModelAdapter(
        $registry,
        $performanceMonitor,
        $queueDetector
    );

    // Register model
    echo "   → Registering queue-anomaly model...\n";
    $queueMetadata = $queueAdapter->registerCurrentModel();
    echo "   ✓ Model registered: {$queueMetadata->modelName} v{$queueMetadata->version->toString()}\n";

    // Test with normal features
    echo "   → Testing with normal job features...\n";
    $normalFeatures = new JobFeatures(
        executionTimeVariance: 0.15,
        memoryUsagePattern: 0.10,
        retryFrequency: 0.0,
        failureRate: 0.05,
        queueDepthCorrelation: 0.10,
        dependencyChainComplexity: 0.08,
        payloadSizeAnomaly: 0.05,
        executionTimingRegularity: 0.30
    );

    $normalResult = $queueAdapter->analyzeWithTracking($normalFeatures, groundTruth: false);
    echo "   ✓ Analysis: " . ($normalResult['is_anomalous'] ? "ANOMALOUS" : "NORMAL") . "\n";
    echo "   ✓ Score: " . sprintf("%.2f%%", $normalResult['anomaly_score'] * 100) . "\n";
    echo "   ✓ Tracking: {$normalResult['tracking']['prediction']} (ground truth: false)\n";

    // Test with anomalous features
    echo "   → Testing with anomalous job features...\n";
    $anomalousFeatures = new JobFeatures(
        executionTimeVariance: 0.85,
        memoryUsagePattern: 0.75,
        retryFrequency: 0.85,
        failureRate: 0.65,
        queueDepthCorrelation: 0.50,
        dependencyChainComplexity: 0.30,
        payloadSizeAnomaly: 0.35,
        executionTimingRegularity: 0.20
    );

    $anomalousResult = $queueAdapter->analyzeWithTracking($anomalousFeatures, groundTruth: true);
    echo "   ✓ Analysis: " . ($anomalousResult['is_anomalous'] ? "ANOMALOUS" : "NORMAL") . "\n";
    echo "   ✓ Score: " . sprintf("%.2f%%", $anomalousResult['anomaly_score'] * 100) . "\n";
    echo "   ✓ Tracking: {$anomalousResult['tracking']['prediction']} (ground truth: true)\n";

    // Get performance metrics
    echo "   → Checking performance metrics...\n";
    $queueMetrics = $queueAdapter->getCurrentPerformanceMetrics();
    echo "   ✓ Total predictions: {$queueMetrics['total_predictions']}\n";
    echo "   ✓ Accuracy: " . sprintf("%.2f%%", $queueMetrics['accuracy'] * 100) . "\n\n";

    // ========================================================================
    // Test 2: WafBehavioralModelAdapter
    // ========================================================================
    echo "3. Testing WafBehavioralModelAdapter...\n";

    // Create detector and adapter
    $wafDetector = new BehaviorAnomalyDetector(
        anomalyThreshold: new Score(0.5),
        zScoreThreshold: 2.5,
        iqrMultiplier: 1.5
    );
    $wafAdapter = new WafBehavioralModelAdapter(
        $registry,
        $performanceMonitor,
        $wafDetector
    );

    // Register model
    echo "   → Registering waf-behavioral model...\n";
    $wafMetadata = $wafAdapter->registerCurrentModel();
    echo "   ✓ Model registered: {$wafMetadata->modelName} v{$wafMetadata->version->toString()}\n";

    // Test with benign request
    echo "   → Testing with benign request features...\n";
    $benignFeatures = new BehaviorFeatures(
        requestFrequency: 0.2,
        endpointDiversity: 2.5,          // Moderate diversity
        parameterEntropy: 3.0,           // Normal entropy
        userAgentConsistency: 0.9,       // Consistent UA
        geographicAnomaly: 0.1,          // Same location
        timePatternRegularity: 0.3,      // Human-like timing
        payloadSimilarity: 0.4,          // Varied payloads
        httpMethodDistribution: 0.6      // Mixed methods
    );

    $benignResult = $wafAdapter->analyzeWithTracking($benignFeatures, historicalBaseline: [], groundTruth: false);
    echo "   ✓ Analysis: " . ($benignResult['is_anomalous'] ? "MALICIOUS" : "BENIGN") . "\n";
    echo "   ✓ Score: " . sprintf("%.2f%%", $benignResult['anomaly_score'] * 100) . "\n";
    echo "   ✓ Tracking: {$benignResult['tracking']['prediction']} (ground truth: false)\n";

    // Test with malicious request
    echo "   → Testing with malicious request features...\n";
    $maliciousFeatures = new BehaviorFeatures(
        requestFrequency: 20.0,          // Very high frequency (>10/s)
        endpointDiversity: 0.5,          // Low diversity (scanning)
        parameterEntropy: 7.0,           // High entropy (probing)
        userAgentConsistency: 0.1,       // Inconsistent UA
        geographicAnomaly: 0.85,         // Suspicious location changes
        timePatternRegularity: 0.95,     // Automated timing
        payloadSimilarity: 0.9,          // Repetitive payloads
        httpMethodDistribution: 0.2      // Limited methods
    );

    $maliciousResult = $wafAdapter->analyzeWithTracking($maliciousFeatures, historicalBaseline: [], groundTruth: true);
    echo "   ✓ Analysis: " . ($maliciousResult['is_anomalous'] ? "MALICIOUS" : "BENIGN") . "\n";
    echo "   ✓ Score: " . sprintf("%.2f%%", $maliciousResult['anomaly_score'] * 100) . "\n";
    echo "   ✓ Tracking: {$maliciousResult['tracking']['prediction']} (ground truth: true)\n";

    // Get performance metrics
    echo "   → Checking performance metrics...\n";
    $wafMetrics = $wafAdapter->getCurrentPerformanceMetrics();
    echo "   ✓ Total predictions: {$wafMetrics['total_predictions']}\n";
    echo "   ✓ Accuracy: " . sprintf("%.2f%%", $wafMetrics['accuracy'] * 100) . "\n\n";

    // ========================================================================
    // Test 3: NPlusOneModelAdapter
    // ========================================================================
    echo "4. Testing NPlusOneModelAdapter...\n";
    echo "   ℹ️  Requires QueryExecutionContext and full NPlusOneDetectionEngine\n";
    echo "   ℹ️  Skipping for now (database-dependent)\n\n";

    // ========================================================================
    // Model Registry Tests
    // ========================================================================
    echo "5. Testing ModelRegistry Integration...\n";

    // List all registered models
    echo "   → Listing registered models...\n";
    $modelNames = $registry->getAllModelNames();
    echo "   ✓ Total model types registered: " . count($modelNames) . "\n";

    foreach ($modelNames as $modelName) {
        $versions = $registry->getAll($modelName);
        foreach ($versions as $metadata) {
            echo "     - {$metadata->modelName} v{$metadata->version->toString()}\n";
            echo "       Type: {$metadata->modelType->value}\n";
            echo "       Created: {$metadata->createdAt->format('Y-m-d H:i:s')}\n";
        }
    }

    // Test model existence
    echo "   → Testing model existence checks...\n";
    $queueExists = $registry->exists('queue-anomaly', \App\Framework\Core\ValueObjects\Version::fromString('1.0.0'));
    $wafExists = $registry->exists('waf-behavioral', \App\Framework\Core\ValueObjects\Version::fromString('1.0.0'));
    echo "   ✓ queue-anomaly exists: " . ($queueExists ? "YES" : "NO") . "\n";
    echo "   ✓ waf-behavioral exists: " . ($wafExists ? "YES" : "NO") . "\n\n";

    // ========================================================================
    // Performance Monitor Tests
    // ========================================================================
    echo "6. Testing ModelPerformanceMonitor Integration...\n";

    // Get metrics for each registered model
    echo "   → Getting metrics for all registered models...\n";
    $allMetrics = [];

    foreach ($modelNames as $modelName) {
        $versions = $registry->getAll($modelName);
        foreach ($versions as $metadata) {
            $metrics = $performanceMonitor->getCurrentMetrics(
                $metadata->modelName,
                $metadata->version
            );
            $modelKey = "{$metadata->modelName}@{$metadata->version->toString()}";
            $allMetrics[$modelKey] = $metrics;
        }
    }

    echo "   ✓ Models tracked: " . count($allMetrics) . "\n";

    foreach ($allMetrics as $modelKey => $metrics) {
        echo "     - $modelKey:\n";
        echo "       Predictions: {$metrics['total_predictions']}\n";
        echo "       Accuracy: " . sprintf("%.2f%%", $metrics['accuracy'] * 100) . "\n";
        if ($metrics['total_predictions'] > 0) {
            echo "       Avg Confidence: " . sprintf("%.2f%%", $metrics['average_confidence'] * 100) . "\n";
        }
    }

    // Check for performance degradation
    echo "\n   → Checking for performance degradation...\n";
    $queueDegradation = $queueAdapter->checkPerformanceDegradation(0.05);
    $wafDegradation = $wafAdapter->checkPerformanceDegradation(0.05);

    echo "   ✓ queue-anomaly degraded: " . ($queueDegradation['has_degraded'] ? "YES" : "NO") . "\n";
    echo "   ✓ waf-behavioral degraded: " . ($wafDegradation['has_degraded'] ? "YES" : "NO") . "\n\n";

    // ========================================================================
    // Test Summary
    // ========================================================================
    echo "=== Test Summary ===\n";
    echo "✓ QueueAnomalyModelAdapter: Working\n";
    echo "✓ WafBehavioralModelAdapter: Working\n";
    echo "✓ NPlusOneModelAdapter: Skipped (database-dependent)\n";
    echo "✓ ModelRegistry: Working\n";
    echo "✓ ModelPerformanceMonitor: Working\n";
    echo "✓ Model registration: Working\n";
    echo "✓ Performance tracking: Working\n";
    echo "✓ Accuracy calculation: Working\n\n";

    echo "Test Results:\n";
    echo "  - Queue Adapter: 2 predictions, " . sprintf("%.0f%%", $queueMetrics['accuracy'] * 100) . " accuracy\n";
    echo "  - WAF Adapter: 2 predictions, " . sprintf("%.0f%%", $wafMetrics['accuracy'] * 100) . " accuracy\n";
    echo "  - Total models registered: " . $registry->getTotalCount() . "\n";
    echo "  - Total predictions tracked: " . array_sum(array_column($allMetrics, 'total_predictions')) . "\n\n";

    echo "=== ML Adapter Tests PASSED ===\n";

} catch (\Throwable $e) {
    echo "\n!!! TEST FAILED !!!\n";
    echo "Error: " . $e->getMessage() . "\n";
    echo "File: " . $e->getFile() . ":" . $e->getLine() . "\n";
    echo "\nStack trace:\n" . $e->getTraceAsString() . "\n";
    exit(1);
}
