<?php

declare(strict_types=1);

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

use App\Framework\Cache\CacheItem;
use App\Framework\Cache\CacheKey;
use App\Framework\Cache\SmartCache;
use App\Framework\Cache\Strategies\AdaptiveTtlCacheStrategy;
use App\Framework\Cache\Strategies\CacheStrategyManager;
use App\Framework\Cache\Strategies\HeatMapCacheStrategy;
use App\Framework\Cache\Strategies\PredictiveCacheStrategy;
use App\Framework\Core\ValueObjects\Duration;

echo "=== Testing Strategy Pattern Advanced Caching ===\n\n";

// Create mock inner cache
$mockCache = new class () implements \App\Framework\Cache\Cache {
    private array $storage = [];

    public function get(\App\Framework\Cache\CacheIdentifier ...$identifiers): \App\Framework\Cache\CacheResult
    {
        $items = [];
        foreach ($identifiers as $identifier) {
            $key = $identifier->toString();
            if (isset($this->storage[$key])) {
                $items[] = \App\Framework\Cache\CacheItem::hit($identifier, $this->storage[$key]['value']);
            } else {
                $items[] = \App\Framework\Cache\CacheItem::miss($identifier);
            }
        }

        return \App\Framework\Cache\CacheResult::fromItems(...$items);
    }

    public function set(\App\Framework\Cache\CacheItem ...$items): bool
    {
        foreach ($items as $item) {
            $this->storage[$item->key->toString()] = [
                'value' => $item->value,
                'ttl' => $item->ttl,
                'set_at' => time(),
            ];
        }

        return true;
    }

    public function has(\App\Framework\Cache\CacheIdentifier ...$identifiers): array
    {
        $results = [];
        foreach ($identifiers as $identifier) {
            $results[$identifier->toString()] = isset($this->storage[$identifier->toString()]);
        }

        return $results;
    }

    public function forget(\App\Framework\Cache\CacheIdentifier ...$identifiers): bool
    {
        foreach ($identifiers as $identifier) {
            unset($this->storage[$identifier->toString()]);
        }

        return true;
    }

    public function clear(): bool
    {
        $this->storage = [];

        return true;
    }

    public function remember(\App\Framework\Cache\CacheKey $key, callable $callback, ?\App\Framework\Core\ValueObjects\Duration $ttl = null): \App\Framework\Cache\CacheItem
    {
        $result = $this->get($key);
        $item = $result->getItem($key);
        if ($item->isHit) {
            return $item;
        }

        $value = $callback();
        $this->set(\App\Framework\Cache\CacheItem::forSet($key, $value, $ttl));

        return \App\Framework\Cache\CacheItem::hit($key, $value);
    }
};

echo "1. Testing Individual Strategies:\n\n";

try {
    // Test AdaptiveTtlCacheStrategy
    echo "   🔧 Testing AdaptiveTtlCacheStrategy:\n";
    $adaptiveStrategy = new AdaptiveTtlCacheStrategy();

    $testKey = CacheKey::fromString('adaptive_test_key');

    // Simulate access pattern
    for ($i = 0; $i < 15; $i++) {
        $adaptiveStrategy->onCacheAccess($testKey, true, Duration::fromMilliseconds(10 + rand(0, 20)));
        usleep(50000); // 0.05 second delay
    }

    $originalTtl = Duration::fromHours(1);
    $adaptedTtl = $adaptiveStrategy->onCacheSet($testKey, "test_value", $originalTtl);

    echo "      ✅ Original TTL: {$originalTtl->toSeconds()}s\n";
    echo "      ✅ Adapted TTL: {$adaptedTtl->toSeconds()}s\n";

    $stats = $adaptiveStrategy->getStats();
    echo "      📊 Tracked keys: {$stats['total_tracked_keys']}\n";
    echo "      📊 Strategy: {$stats['strategy']}\n\n";

} catch (\Throwable $e) {
    echo "      ❌ Error testing AdaptiveTtlCacheStrategy: {$e->getMessage()}\n\n";
}

try {
    // Test HeatMapCacheStrategy
    echo "   🌡️ Testing HeatMapCacheStrategy:\n";
    $heatMapStrategy = new HeatMapCacheStrategy();

    $hotKey = CacheKey::fromString('hot_cache_key');
    $coldKey = CacheKey::fromString('cold_cache_key');

    // Hot key - many accesses
    for ($i = 0; $i < 30; $i++) {
        $heatMapStrategy->onCacheAccess($hotKey, true, Duration::fromMilliseconds(5 + rand(0, 10)));
        usleep(10000);
    }

    // Cold key - few accesses
    for ($i = 0; $i < 2; $i++) {
        $heatMapStrategy->onCacheAccess($coldKey, true, Duration::fromMilliseconds(50 + rand(0, 30)));
        usleep(100000);
    }

    $stats = $heatMapStrategy->getStats();
    echo "      ✅ Total tracked keys: {$stats['total_tracked_keys']}\n";
    echo "      ✅ Strategy: {$stats['strategy']}\n";

    $analysis = $stats['analysis'];
    echo "      🔥 Hot keys found: " . count($analysis['hot_keys']) . "\n";
    echo "      🧊 Cold keys found: " . count($analysis['cold_keys']) . "\n";
    echo "      ⚠️ Performance insights: " . count($analysis['performance_insights']) . "\n\n";

} catch (\Throwable $e) {
    echo "      ❌ Error testing HeatMapCacheStrategy: {$e->getMessage()}\n\n";
}

try {
    // Test PredictiveCacheStrategy
    echo "   🔮 Testing PredictiveCacheStrategy:\n";
    $predictiveStrategy = new PredictiveCacheStrategy();

    $predictKey = CacheKey::fromString('predictive_test_key');

    // Register warming callback
    $predictiveStrategy->registerWarmingCallback($predictKey, function () {
        return ['id' => 123, 'name' => 'Test User', 'email' => 'test@example.com'];
    });

    // Simulate regular access pattern
    for ($i = 0; $i < 8; $i++) {
        $predictiveStrategy->onCacheAccess($predictKey, true, Duration::fromMilliseconds(15 + rand(0, 25)));
        usleep(30000);
    }

    $predictions = $predictiveStrategy->generatePredictions();
    echo "      ✅ Generated predictions: " . count($predictions) . "\n";

    if (! empty($predictions)) {
        $topPrediction = $predictions[0];
        echo "      🎯 Top prediction confidence: " . round($topPrediction['confidence'], 3) . "\n";
        echo "      🎯 Prediction reason: {$topPrediction['reason']}\n";
    }

    $stats = $predictiveStrategy->getStats();
    echo "      📊 Total patterns: {$stats['total_patterns']}\n";
    echo "      📊 Strategy: {$stats['strategy']}\n\n";

} catch (\Throwable $e) {
    echo "      ❌ Error testing PredictiveCacheStrategy: {$e->getMessage()}\n\n";
}

echo "2. Testing Strategy Manager:\n\n";

try {
    // Test CacheStrategyManager
    echo "   🎯 Testing CacheStrategyManager:\n";

    $strategyManager = new CacheStrategyManager();
    $strategyManager->addStrategy(new AdaptiveTtlCacheStrategy());
    $strategyManager->addStrategy(new HeatMapCacheStrategy());
    $strategyManager->addStrategy(new PredictiveCacheStrategy());

    echo "      ✅ Strategies registered: {$strategyManager->getStrategyCount()}\n";

    $testKey = CacheKey::fromString('manager_test_key');

    // Test access notification
    $strategyManager->notifyAccess($testKey, true, Duration::fromMilliseconds(20));

    // Test set notification with TTL modification
    $originalTtl = Duration::fromMinutes(30);
    $finalTtl = $strategyManager->notifySet($testKey, "test_value", $originalTtl);

    echo "      ✅ Original TTL: {$originalTtl->toSeconds()}s\n";
    echo "      ✅ Final TTL after strategies: {$finalTtl->toSeconds()}s\n";

    $managerStats = $strategyManager->getStats();
    echo "      📊 Enabled strategies: {$managerStats['strategy_manager']['enabled_strategies']}\n";
    echo "      📊 Strategy names: " . implode(', ', $managerStats['strategy_manager']['strategy_names']) . "\n\n";

} catch (\Throwable $e) {
    echo "      ❌ Error testing CacheStrategyManager: {$e->getMessage()}\n\n";
}

echo "3. Testing SmartCache with Strategies:\n\n";

try {
    // Test SmartCache with default strategies
    echo "   🚀 Testing SmartCache with Default Strategies:\n";

    $smartCache = SmartCache::withDefaultStrategies($mockCache);

    echo "      ✅ SmartCache created with strategy support\n";

    $testKey = CacheKey::fromString('smart_cache_test');

    // Test remember with strategy integration
    $result = $smartCache->remember($testKey, function () {
        return ['data' => 'Smart cache test value', 'timestamp' => time()];
    }, Duration::fromMinutes(15));

    echo "      ✅ Cache remember successful: " . ($result->isHit ? 'Hit' : 'Miss') . "\n";

    // Simulate multiple accesses to build patterns
    for ($i = 0; $i < 10; $i++) {
        $smartCache->get($testKey);
        usleep(25000);
    }

    // Get comprehensive stats
    $stats = $smartCache->getStats();
    echo "      📊 Cache type: {$stats['cache_type']}\n";
    echo "      📊 Strategy support: " . ($stats['strategy_support'] ? 'Yes' : 'No') . "\n";

    if (isset($stats['strategy_stats'])) {
        $strategyStats = $stats['strategy_stats'];
        echo "      📊 Total strategies: {$strategyStats['strategy_manager']['total_strategies']}\n";
        echo "      📊 Enabled strategies: {$strategyStats['strategy_manager']['enabled_strategies']}\n";
    }

    echo "\n";

} catch (\Throwable $e) {
    echo "      ❌ Error testing SmartCache with strategies: {$e->getMessage()}\n\n";
}

echo "4. Testing Performance-Focused Configuration:\n\n";

try {
    // Test performance-focused strategy configuration
    echo "   ⚡ Testing Performance-Focused Configuration:\n";

    $performanceCache = SmartCache::withPerformanceStrategies($mockCache);

    $perfKey = CacheKey::fromString('performance_test_key');

    // Simulate high-frequency access
    for ($i = 0; $i < 20; $i++) {
        $performanceCache->remember($perfKey, function () use ($i) {
            return ['iteration' => $i, 'data' => str_repeat('x', 100)];
        }, Duration::fromMinutes(5));
        usleep(10000);
    }

    $adaptiveStats = $performanceCache->getStrategyStats('adaptive_ttl');
    if ($adaptiveStats) {
        echo "      ⚡ Adaptive TTL extension factor: {$adaptiveStats['adaptation_factors']['extension_factor']}\n";
        echo "      ⚡ Adaptive TTL reduction factor: {$adaptiveStats['adaptation_factors']['reduction_factor']}\n";
    }

    $heatMapStats = $performanceCache->getStrategyStats('heat_map');
    if ($heatMapStats) {
        echo "      🌡️ Heat map hot threshold: {$heatMapStats['thresholds']['hot_threshold']}\n";
        echo "      🌡️ Heat map max tracked keys: {$heatMapStats['max_tracked_keys']}\n";
    }

    echo "      ✅ Performance configuration tested successfully\n\n";

} catch (\Throwable $e) {
    echo "      ❌ Error testing performance configuration: {$e->getMessage()}\n\n";
}

echo "5. Testing Development-Focused Configuration:\n\n";

try {
    // Test development-focused strategy configuration
    echo "   🔧 Testing Development-Focused Configuration:\n";

    $devCache = SmartCache::withDevelopmentStrategies($mockCache);

    $devKey = CacheKey::fromString('development_test_key');

    // Test with detailed tracking
    for ($i = 0; $i < 8; $i++) {
        $devCache->set(CacheItem::forSet($devKey, "dev_value_{$i}", Duration::fromMinutes(10)));
        $devCache->get($devKey);
        usleep(50000);
    }

    $devStats = $devCache->getStats();
    if (isset($devStats['strategy_stats']['strategies']['heat_map'])) {
        $heatStats = $devStats['strategy_stats']['strategies']['heat_map'];
        echo "      🔧 Heat map analysis window: {$heatStats['thresholds']['analysis_window_hours']} hours\n";
        echo "      🔧 Max tracked keys: {$heatStats['max_tracked_keys']}\n";
    }

    if (isset($devStats['strategy_stats']['strategies']['predictive'])) {
        $predictStats = $devStats['strategy_stats']['strategies']['predictive'];
        echo "      🔮 Prediction window: {$predictStats['prediction_window_hours']} hours\n";
        echo "      🔮 Confidence threshold: {$predictStats['confidence_threshold']}\n";
    }

    echo "      ✅ Development configuration tested successfully\n\n";

} catch (\Throwable $e) {
    echo "      ❌ Error testing development configuration: {$e->getMessage()}\n\n";
}

echo "=== Strategy Pattern Advanced Caching Test Completed ===\n";
echo "\n🎯 Summary of Strategy Pattern Implementation:\n";
echo "   1. ✅ Individual strategies work independently\n";
echo "   2. ✅ CacheStrategyManager orchestrates multiple strategies\n";
echo "   3. ✅ SmartCache integrates strategies seamlessly\n";
echo "   4. ✅ Pre-configured strategy sets (Default, Performance, Development)\n";
echo "   5. ✅ Composable and modular strategy system\n";
echo "\n💡 The Strategy Pattern provides:\n";
echo "   • Modular cache optimization strategies\n";
echo "   • Composable cache intelligence\n";
echo "   • Configurable strategy combinations\n";
echo "   • Separation of concerns for cache behavior\n";
echo "   • Easy testing and extensibility\n";
