<?php

declare(strict_types=1);

/**
 * ML API Endpoints Test
 *
 * Tests all ML Management REST API endpoints:
 * 1. Model registration and listing
 * 2. Performance metrics retrieval
 * 3. A/B testing workflows
 * 4. Auto-tuning optimization
 * 5. Dashboard data endpoints
 */

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

use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Core\ValueObjects\Timestamp;
use App\Framework\Core\ValueObjects\Version;
use App\Framework\Http\HttpRequest;
use App\Framework\Http\Method;
use App\Framework\Http\RequestBody;
use App\Framework\Http\Headers;
use App\Framework\MachineLearning\ModelManagement\ABTestingService;
use App\Framework\MachineLearning\ModelManagement\AutoTuningEngine;
use App\Framework\MachineLearning\ModelManagement\CacheModelRegistry;
use App\Framework\MachineLearning\ModelManagement\CachePerformanceStorage;
use App\Framework\MachineLearning\ModelManagement\InMemoryPerformanceStorage;
use App\Framework\MachineLearning\ModelManagement\LogAlertingService;
use App\Framework\MachineLearning\ModelManagement\ModelPerformanceMonitor;
use App\Framework\MachineLearning\ModelManagement\ValueObjects\ModelMetadata;
use App\Framework\MachineLearning\ModelManagement\ValueObjects\ModelType;
use App\Framework\Random\SecureRandomGenerator;
use App\Application\Api\MachineLearning\MLModelsController;
use App\Application\Api\MachineLearning\MLABTestingController;
use App\Application\Api\MachineLearning\MLAutoTuningController;
use App\Application\Api\MachineLearning\MLDashboardController;
use App\Framework\Cache\Driver\InMemoryCache;
use App\Framework\Cache\GeneralCache;
use App\Framework\Serializer\Php\PhpSerializer;
use App\Framework\Serializer\Php\PhpSerializerConfig;

echo "=== ML API Endpoints Test ===\n\n";

// Helper function to create HTTP requests easily
function createRequest(string $method, string $path, array $data = [], array $queryParams = []): HttpRequest
{
    $methodEnum = Method::from($method);
    $headers = new Headers();
    $body = !empty($data) ? json_encode($data) : '';

    return new HttpRequest(
        method: $methodEnum,
        headers: $headers,
        body: $body,
        path: $path,
        queryParams: $queryParams,
        parsedBody: new RequestBody($methodEnum, $headers, $body, $data)
    );
}

try {
    // ========================================================================
    // Setup: Initialize services
    // ========================================================================
    echo "1. Initializing ML services...\n";

    $cacheDriver = new InMemoryCache();
    $serializer = new PhpSerializer(PhpSerializerConfig::safe());
    $cache = new GeneralCache($cacheDriver, $serializer);
    $registry = new CacheModelRegistry($cache, ttlDays: 7);
    $storage = new InMemoryPerformanceStorage();
    $alerting = new LogAlertingService();
    $performanceMonitor = new ModelPerformanceMonitor($registry, $storage, $alerting);
    $random = new SecureRandomGenerator();
    $abTesting = new ABTestingService($random, $registry);
    $autoTuning = new AutoTuningEngine($performanceMonitor, $registry, $storage);

    // Initialize controllers
    $modelsController = new MLModelsController($registry, $performanceMonitor);
    $abTestingController = new MLABTestingController($abTesting, $registry);
    $autoTuningController = new MLAutoTuningController($autoTuning, $registry);
    $dashboardController = new MLDashboardController($registry, $performanceMonitor);

    echo "   ✓ All services initialized\n";
    echo "   ✓ All controllers created\n\n";

    // ========================================================================
    // Test 1: Model Registration (POST /api/ml/models)
    // ========================================================================
    echo "2. Testing model registration endpoint...\n";

    $registerRequest = createRequest(
        method: 'POST',
        path: '/api/ml/models',
        data: [
            'model_name' => 'test-fraud-detector',
            'type' => 'supervised',
            'version' => '1.0.0',
            'configuration' => [
                'threshold' => 0.7,
                'algorithm' => 'random_forest',
            ],
            'performance_metrics' => [
                'accuracy' => 0.92,
                'precision' => 0.89,
            ],
        ]
    );

    $registerResponse = $modelsController->registerModel($registerRequest);
    $registerData = $registerResponse->data;

    echo "   → POST /api/ml/models\n";
    echo "      Status: {$registerResponse->status->value}\n";
    echo "      Model: {$registerData['model_name']}\n";
    echo "      Version: {$registerData['version']}\n";
    echo "      Message: {$registerData['message']}\n\n";

    // ========================================================================
    // Test 2: List Models (GET /api/ml/models)
    // ========================================================================
    echo "3. Testing list models endpoint...\n";

    // Register additional models for testing
    $additionalModels = [
        ['name' => 'spam-classifier', 'type' => 'supervised', 'version' => '2.0.0'],
        ['name' => 'anomaly-detector', 'type' => 'unsupervised', 'version' => '1.5.0'],
    ];

    foreach ($additionalModels as $modelData) {
        $metadata = new ModelMetadata(
            modelName: $modelData['name'],
            modelType: $modelData['type'] === 'supervised' ? ModelType::SUPERVISED : ModelType::UNSUPERVISED,
            version: Version::fromString($modelData['version']),
            configuration: ['threshold' => 0.75],
            createdAt: Timestamp::now()
        );
        $registry->register($metadata);
    }

    $listRequest = createRequest(
        method: 'GET',
        path: '/api/ml/models'
    );

    $listResponse = $modelsController->listModels($listRequest);
    $listData = $listResponse->data;

    echo "   → GET /api/ml/models\n";
    echo "      Status: {$listResponse->status->value}\n";
    echo "      Total Models: {$listData['total_models']}\n";
    foreach ($listData['models'] as $model) {
        echo "      - {$model['model_name']} ({$model['type']}) - {$model['versions'][0]['version']}\n";
    }
    echo "\n";

    // ========================================================================
    // Test 3: Get Model Metrics (GET /api/ml/models/{modelName}/metrics)
    // ========================================================================
    echo "4. Testing model metrics endpoint...\n";

    // Simulate predictions for test-fraud-detector
    $timestamp = Timestamp::now();
    for ($i = 0; $i < 100; $i++) {
        $storage->storePrediction([
            'model_name' => 'test-fraud-detector',
            'version' => '1.0.0',
            'prediction' => $i < 92,
            'actual' => $i < 92,
            'confidence' => 0.85,
            'features' => [],
            'timestamp' => $timestamp->toDateTime(),
            'is_correct' => true,
        ]);
    }

    $metricsRequest = createRequest(
        method: 'GET',
        path: '/api/ml/models/test-fraud-detector/metrics',
        queryParams: ['version' => '1.0.0', 'timeWindow' => '1']
    );

    $metricsResponse = $modelsController->getMetrics('test-fraud-detector', $metricsRequest);
    $metricsData = $metricsResponse->data;

    echo "   → GET /api/ml/models/test-fraud-detector/metrics\n";
    echo "      Status: {$metricsResponse->status->value}\n";
    echo "      Accuracy: " . sprintf("%.2f%%", $metricsData['metrics']['accuracy'] * 100) . "\n";
    echo "      Total Predictions: {$metricsData['metrics']['total_predictions']}\n\n";

    // ========================================================================
    // Test 4: A/B Test Creation (POST /api/ml/ab-test)
    // ========================================================================
    echo "5. Testing A/B test creation endpoint...\n";

    // Register version 2.0.0 for A/B testing
    $v2Metadata = new ModelMetadata(
        modelName: 'test-fraud-detector',
        modelType: ModelType::SUPERVISED,
        version: Version::fromString('2.0.0'),
        configuration: ['threshold' => 0.75],
        createdAt: Timestamp::now(),
        performanceMetrics: ['accuracy' => 0.95]
    );
    $registry->register($v2Metadata);

    $abTestRequest = createRequest(
        method: 'POST',
        path: '/api/ml/ab-test',
        data: [
            'model_name' => 'test-fraud-detector',
            'version_a' => '1.0.0',
            'version_b' => '2.0.0',
            'traffic_split_a' => 0.5,
            'primary_metric' => 'accuracy',
        ]
    );

    $abTestResponse = $abTestingController->startTest($abTestRequest);
    $abTestData = $abTestResponse->data;

    echo "   → POST /api/ml/ab-test\n";
    echo "      Status: {$abTestResponse->status->value}\n";
    echo "      Test ID: {$abTestData['test_id']}\n";
    echo "      Version A Traffic: " . ($abTestData['traffic_split']['version_a'] * 100) . "%\n";
    echo "      Version B Traffic: " . ($abTestData['traffic_split']['version_b'] * 100) . "%\n\n";

    // ========================================================================
    // Test 5: Rollout Plan Generation (POST /api/ml/ab-test/rollout-plan)
    // ========================================================================
    echo "6. Testing rollout plan generation endpoint...\n";

    $rolloutRequest = createRequest(
        method: 'POST',
        path: '/api/ml/ab-test/rollout-plan',
        data: [
            'model_name' => 'test-fraud-detector',
            'current_version' => '1.0.0',
            'new_version' => '2.0.0',
            'steps' => 4,
        ]
    );

    $rolloutResponse = $abTestingController->generateRolloutPlan($rolloutRequest);
    $rolloutData = $rolloutResponse->data;

    echo "   → POST /api/ml/ab-test/rollout-plan\n";
    echo "      Status: {$rolloutResponse->status->value}\n";
    echo "      Total Stages: {$rolloutData['total_stages']}\n";
    foreach ($rolloutData['rollout_stages'] as $stage) {
        echo "      Stage {$stage['stage']}: Current {$stage['current_version_traffic']}% / New {$stage['new_version_traffic']}%\n";
    }
    echo "\n";

    // ========================================================================
    // Test 6: Threshold Optimization (POST /api/ml/optimize/threshold)
    // ========================================================================
    echo "7. Testing threshold optimization endpoint...\n";

    // Add more diverse predictions for optimization
    for ($i = 0; $i < 100; $i++) {
        $confidence = 0.5 + ($i / 100) * 0.4; // 0.5 to 0.9
        $prediction = $confidence >= 0.7;
        $actual = $i < 85;

        $storage->storePrediction([
            'model_name' => 'test-fraud-detector',
            'version' => '1.0.0',
            'prediction' => $prediction,
            'actual' => $actual,
            'confidence' => $confidence,
            'features' => [],
            'timestamp' => $timestamp->toDateTime(),
            'is_correct' => $prediction === $actual,
        ]);
    }

    $optimizeRequest = createRequest(
        method: 'POST',
        path: '/api/ml/optimize/threshold',
        data: [
            'model_name' => 'test-fraud-detector',
            'version' => '1.0.0',
            'metric_to_optimize' => 'f1_score',
            'threshold_range' => [0.5, 0.9],
            'step' => 0.1,
        ]
    );

    $optimizeResponse = $autoTuningController->optimizeThreshold($optimizeRequest);
    $optimizeData = $optimizeResponse->data;

    echo "   → POST /api/ml/optimize/threshold\n";
    echo "      Status: {$optimizeResponse->status->value}\n";
    echo "      Current Threshold: {$optimizeData['current_threshold']}\n";
    echo "      Optimal Threshold: {$optimizeData['optimal_threshold']}\n";
    echo "      Improvement: " . sprintf("%.1f%%", $optimizeData['improvement_percent']) . "\n";
    echo "      Tested Thresholds: {$optimizeData['tested_thresholds']}\n\n";

    // ========================================================================
    // Test 7: Dashboard Data (GET /api/ml/dashboard)
    // ========================================================================
    echo "8. Testing dashboard data endpoint...\n";

    $dashboardRequest = createRequest(
        method: 'GET',
        path: '/api/ml/dashboard',
        queryParams: ['timeWindow' => '24']
    );

    $dashboardResponse = $dashboardController->getDashboardData($dashboardRequest);
    $dashboardData = $dashboardResponse->data;

    echo "   → GET /api/ml/dashboard\n";
    echo "      Status: {$dashboardResponse->status->value}\n";
    echo "      Total Models: {$dashboardData['summary']['total_models']}\n";
    echo "      Healthy: {$dashboardData['summary']['healthy_models']}\n";
    echo "      Degraded: {$dashboardData['summary']['degraded_models']}\n";
    echo "      Average Accuracy: " . sprintf("%.2f%%", $dashboardData['summary']['average_accuracy'] * 100) . "\n";
    echo "      Overall Status: {$dashboardData['summary']['overall_status']}\n";
    echo "      Active Alerts: " . count($dashboardData['alerts']) . "\n\n";

    // ========================================================================
    // Test 8: Health Indicators (GET /api/ml/dashboard/health)
    // ========================================================================
    echo "9. Testing health indicators endpoint...\n";

    $healthResponse = $dashboardController->getHealthIndicators();
    $healthData = $healthResponse->data;

    echo "   → GET /api/ml/dashboard/health\n";
    echo "      Status: {$healthResponse->status->value}\n";
    echo "      Overall Status: {$healthData['overall_status']}\n";
    echo "      Health Percentage: {$healthData['health_percentage']}%\n";
    echo "      Healthy Models: {$healthData['healthy_models']}\n";
    echo "      Degraded Models: {$healthData['degraded_models']}\n";
    echo "      Critical Models: {$healthData['critical_models']}\n\n";

    // ========================================================================
    // Test 9: Registry Summary (GET /api/ml/dashboard/registry-summary)
    // ========================================================================
    echo "10. Testing registry summary endpoint...\n";

    $summaryResponse = $dashboardController->getRegistrySummary();
    $summaryData = $summaryResponse->data;

    echo "   → GET /api/ml/dashboard/registry-summary\n";
    echo "      Status: {$summaryResponse->status->value}\n";
    echo "      Total Models: {$summaryData['total_models']}\n";
    echo "      Total Versions: {$summaryData['total_versions']}\n";
    echo "      By Type:\n";
    foreach ($summaryData['by_type'] as $type => $count) {
        echo "        - {$type}: {$count}\n";
    }
    echo "\n";

    // ========================================================================
    // Test Summary
    // ========================================================================
    echo "=== Test Summary ===\n";
    echo "✓ Model Registration: Working\n";
    echo "✓ List Models: Working\n";
    echo "✓ Get Model Metrics: Working\n";
    echo "✓ A/B Test Creation: Working\n";
    echo "✓ Rollout Plan Generation: Working\n";
    echo "✓ Threshold Optimization: Working\n";
    echo "✓ Dashboard Data: Working\n";
    echo "✓ Health Indicators: Working\n";
    echo "✓ Registry Summary: Working\n\n";

    echo "API Endpoints Tested: 9\n";
    echo "All endpoints returning 200/201 status codes\n\n";

    echo "=== ML API Endpoints Test 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);
}
