<?php

declare(strict_types=1);

/**
 * Test script for Memory-Aware Caching System
 */

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

use App\Framework\Cache\Driver\InMemoryCache;
use App\Framework\Cache\GeneralCache;
use App\Framework\Core\Events\EventDispatcher;
use App\Framework\Core\ValueObjects\Byte;
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\DateTime\SystemClock;
use App\Framework\Discovery\Cache\MemoryAwareCacheManager;
use App\Framework\Discovery\Cache\TieredCacheManager;
use App\Framework\Discovery\Memory\DiscoveryMemoryManager;
use App\Framework\Discovery\ValueObjects\CacheLevel;
use App\Framework\Discovery\ValueObjects\CacheTier;
use App\Framework\Discovery\ValueObjects\CompressionLevel;
use App\Framework\Discovery\ValueObjects\MemoryStrategy;
use App\Framework\Logging\DefaultLogger;
use App\Framework\Logging\Handlers\ConsoleHandler;
use App\Framework\Logging\LogLevel;
use App\Framework\Performance\MemoryMonitor;
use App\Framework\Serializer\Php\PhpSerializer;

echo "🧪 Testing Memory-Aware Caching System\n";
echo "=====================================\n";

try {
    // Setup basic dependencies
    $cacheDriver = new InMemoryCache();
    $serializer = new PhpSerializer();
    $cache = new GeneralCache($cacheDriver, $serializer);
    $clock = new SystemClock();
    $eventDispatcher = new EventDispatcher();

    // Setup logging
    $consoleHandler = new ConsoleHandler();
    $logger = new DefaultLogger(LogLevel::INFO, [$consoleHandler]);

    // Setup memory management
    $memoryLimit = Byte::fromMegabytes(32); // Small limit to trigger events
    $strategy = MemoryStrategy::ADAPTIVE;
    $memoryMonitor = new MemoryMonitor();

    $memoryManager = new DiscoveryMemoryManager(
        strategy: $strategy,
        memoryLimit: $memoryLimit,
        memoryPressureThreshold: 0.6, // Lower threshold for testing
        memoryMonitor: $memoryMonitor,
        logger: $logger,
        eventDispatcher: $eventDispatcher,
        clock: $clock
    );

    echo "✅ Dependencies initialized\n";

    // Test 1: Memory-Aware Cache Manager
    echo "\n🧪 Test 1: Memory-Aware Cache Manager\n";

    $memoryAwareCache = new MemoryAwareCacheManager(
        cache: $cache,
        memoryManager: $memoryManager,
        clock: $clock,
        logger: $logger,
        eventDispatcher: $eventDispatcher,
        defaultTtl: Duration::fromMinutes(30),
        compressionThreshold: 0.5, // Low threshold for testing
        evictionThreshold: 0.7
    );

    echo "✅ Memory-aware cache manager created\n";

    // Store some test data with different characteristics
    $testData = [
        'small_frequent' => str_repeat('A', 100),      // Small data
        'medium_data' => str_repeat('B', 1000),        // Medium data
        'large_data' => str_repeat('C', 10000),        // Large data
        'huge_data' => str_repeat('D', 50000),          // Very large data
    ];

    foreach ($testData as $key => $data) {
        $success = $memoryAwareCache->store($key, $data);
        echo "  Stored {$key}: " . ($success ? '✅' : '❌') . " (" . strlen($data) . " bytes)\n";
    }

    // Test retrieval
    echo "\nTesting data retrieval:\n";
    foreach (array_keys($testData) as $key) {
        $retrieved = $memoryAwareCache->get($key);
        $success = $retrieved === $testData[$key];
        echo "  Retrieved {$key}: " . ($success ? '✅' : '❌') . "\n";
    }

    // Test memory pressure management
    echo "\n🧪 Test 2: Memory Pressure Management\n";

    $managementResult = $memoryAwareCache->performMemoryPressureManagement();
    echo "✅ Memory pressure management completed\n";
    echo "  Actions performed: " . count($managementResult->actionsPerformed) . "\n";
    echo "  Memory freed: " . $managementResult->memoryFreed->toHumanReadable() . "\n";
    echo "  Cache level: " . $managementResult->cacheLevel->value . "\n";

    // Get cache statistics
    $cacheMetrics = $memoryAwareCache->getCacheStatistics();
    echo "\n📊 Cache Metrics:\n";
    echo "  Total items: " . $cacheMetrics->totalItems . "\n";
    echo "  Hit rate: " . $cacheMetrics->hitRate->toPercentage()->toString() . "\n";
    echo "  Total size: " . $cacheMetrics->totalSize->toHumanReadable() . "\n";
    echo "  Compression ratio: " . $cacheMetrics->compressionRatio->toPercentage()->toString() . "\n";
    echo "  Memory pressure impact: " . $cacheMetrics->getMemoryPressureImpact() . "\n";
    echo "  Health status: " . $cacheMetrics->getHealthStatus() . "\n";
    echo "  Quality score: " . $cacheMetrics->getQualityScore()->toString() . "\n";

    // Test 3: Tiered Cache Manager
    echo "\n🧪 Test 3: Tiered Cache Manager\n";

    $tieredCache = new TieredCacheManager(
        cache: $cache,
        memoryManager: $memoryManager,
        clock: $clock,
        logger: $logger,
        eventDispatcher: $eventDispatcher
    );

    echo "✅ Tiered cache manager created\n";

    // Test automatic tier assignment
    $tieredTestData = [
        'hot_small' => ['data' => str_repeat('H', 50), 'expected_tier' => CacheTier::HOT],
        'warm_medium' => ['data' => str_repeat('W', 500), 'expected_tier' => CacheTier::WARM],
        'cold_large' => ['data' => str_repeat('C', 5000), 'expected_tier' => CacheTier::COLD],
        'archive_huge' => ['data' => str_repeat('A', 50000), 'expected_tier' => CacheTier::ARCHIVE],
    ];

    foreach ($tieredTestData as $key => $testInfo) {
        $success = $tieredCache->store($key, $testInfo['data']);
        echo "  Stored {$key} (expected {$testInfo['expected_tier']->value}): " .
             ($success ? '✅' : '❌') . " (" . strlen($testInfo['data']) . " bytes)\n";
    }

    // Test tier retrieval
    echo "\nTesting tiered data retrieval:\n";
    foreach (array_keys($tieredTestData) as $key) {
        $retrieved = $tieredCache->get($key);
        $success = $retrieved === $tieredTestData[$key]['data'];
        echo "  Retrieved {$key}: " . ($success ? '✅' : '❌') . "\n";
    }

    // Test tier management
    echo "\n🧪 Test 4: Tier Management\n";

    $tierResult = $tieredCache->performTierManagement();
    echo "✅ Tier management completed\n";
    echo "  Actions performed: " . count($tierResult->actionsPerformed) . "\n";
    echo "  Items moved: " . $tierResult->itemsMoved . "\n";
    echo "  Memory freed: " . $tierResult->memoryFreed->toHumanReadable() . "\n";
    echo "  Effectiveness: " . $tierResult->getEffectiveness() . "\n";

    // Get tier statistics
    $tierStats = $tieredCache->getTierStatistics();
    echo "\n📊 Tier Statistics:\n";
    foreach ($tierStats['tiers'] as $tierName => $stats) {
        echo "  {$tierName} tier:\n";
        echo "    Items: {$stats['item_count']}\n";
        echo "    Size: {$stats['total_size']}\n";
        echo "    Hit rate: " . round($stats['hit_rate'] * 100, 1) . "%\n";
        echo "    Health: {$stats['tier_health']}\n";
    }

    echo "\n  Overall:\n";
    echo "    Total items: {$tierStats['overall']['total_items']}\n";
    echo "    Tier efficiency: " . $tierStats['overall']['tier_efficiency']->toString() . "\n";

    // Test 5: Value Objects
    echo "\n🧪 Test 5: Value Objects Testing\n";

    // Test CacheLevel
    echo "Testing CacheLevel:\n";
    foreach (CacheLevel::cases() as $level) {
        echo "  {$level->value}: retention=" . $level->getRetentionMultiplier() .
             ", compression=" . ($level->requiresCompression() ? 'yes' : 'no') .
             ", desc=" . $level->getDescription() . "\n";
    }

    // Test CacheTier
    echo "\nTesting CacheTier:\n";
    foreach (CacheTier::cases() as $tier) {
        echo "  {$tier->value}: compression=" . $tier->getCompressionLevel()->value .
             ", ttl_mult=" . $tier->getTtlMultiplier() .
             ", priority=" . $tier->getPriority() . "\n";
    }

    // Test CompressionLevel
    echo "\nTesting CompressionLevel:\n";
    foreach (CompressionLevel::cases() as $level) {
        echo "  {$level->value}: gzip_level=" . $level->getGzipLevel() .
             ", expected_ratio=" . round($level->getExpectedRatio() * 100, 1) . "%" .
             ", cpu_cost=" . $level->getCpuCostMultiplier() . "x\n";
    }

    // Test 6: Memory Pressure Simulation
    echo "\n🧪 Test 6: Memory Pressure Simulation\n";

    // Store increasingly large data to trigger memory pressure
    for ($i = 1; $i <= 5; $i++) {
        $largeData = str_repeat("PRESSURE_TEST_{$i}_", 10000 * $i);
        $key = "pressure_test_{$i}";

        $memoryAwareCache->store($key, $largeData);
        $memoryStatus = $memoryManager->getMemoryStatus("pressure_test_{$i}");

        echo "  Iteration {$i}: " .
             "pressure=" . $memoryStatus->memoryPressure->toString() .
             ", status=" . $memoryStatus->status->value .
             ", size=" . round(strlen($largeData) / 1024, 1) . "KB\n";

        // Perform management if pressure is high
        if ($memoryStatus->memoryPressure->toDecimal() > 0.7) {
            $managementResult = $memoryAwareCache->performMemoryPressureManagement();
            echo "    → Management performed: " . $managementResult->getSummary() . "\n";
        }
    }

    echo "\n🎉 All memory-aware caching tests completed successfully!\n";
    echo "\n🏆 Key Features Verified:\n";
    echo "  ✅ Memory-aware cache storage and retrieval\n";
    echo "  ✅ Automatic compression based on memory pressure\n";
    echo "  ✅ Cache level adjustment based on memory status\n";
    echo "  ✅ Memory pressure management and cleanup\n";
    echo "  ✅ Tiered caching with automatic tier assignment\n";
    echo "  ✅ Tier-specific compression and TTL strategies\n";
    echo "  ✅ Tier management and optimization\n";
    echo "  ✅ Cache metrics with Score Value Objects\n";
    echo "  ✅ Value object integration and validation\n";
    echo "  ✅ Memory pressure simulation and response\n";

} catch (Throwable $e) {
    echo "\n❌ Error during caching system testing:\n";
    echo "  Message: " . $e->getMessage() . "\n";
    echo "  File: " . $e->getFile() . ":" . $e->getLine() . "\n";
    echo "  Stack trace:\n" . $e->getTraceAsString() . "\n";
    exit(1);
}
