<?php

declare(strict_types=1);

namespace App\Framework\Cache\Warming\Strategies;

use App\Framework\Cache\Cache;
use App\Framework\Cache\CacheKey;
use App\Framework\Cache\CacheItem;
use App\Framework\Cache\Warming\ValueObjects\WarmupPriority;
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Router\CompiledRoutes;
use App\Framework\Config\Environment;

/**
 * Warms critical application paths that must be cached for optimal performance
 *
 * This strategy loads:
 * - Compiled routes
 * - Framework configuration
 * - Environment variables
 * - Common application settings
 */
final readonly class CriticalPathWarmingStrategy extends BaseWarmupStrategy
{
    public function __construct(
        Cache $cache,
        private CompiledRoutes $compiledRoutes,
        private Environment $environment
    ) {
        parent::__construct($cache);
    }

    public function getName(): string
    {
        return 'critical_path';
    }

    public function getPriority(): int
    {
        return WarmupPriority::CRITICAL->value;
    }

    protected function getItemsToWarm(): array
    {
        return [
            [
                'key' => 'routes_static',
                'loader' => fn() => $this->compiledRoutes->getStaticRoutes(),
                'ttl' => Duration::fromDays(7)
            ],
            [
                'key' => 'routes_dynamic',
                'loader' => fn() => $this->compiledRoutes->getDynamicRoutes(),
                'ttl' => Duration::fromDays(7)
            ],
            [
                'key' => 'framework_config',
                'loader' => fn() => $this->loadFrameworkConfig(),
                'ttl' => Duration::fromHours(24)
            ],
            [
                'key' => 'env_variables',
                'loader' => fn() => $this->loadEnvironmentVariables(),
                'ttl' => Duration::fromHours(24)
            ]
        ];
    }

    protected function warmItem(mixed $item): void
    {
        if (!is_array($item) || !isset($item['key'], $item['loader'], $item['ttl'])) {
            throw new \InvalidArgumentException('Invalid warmup item structure');
        }

        $key = CacheKey::fromString($item['key']);
        $data = $item['loader']();
        $ttl = $item['ttl'];

        $cacheItem = CacheItem::forSetting(
            key: $key,
            value: $data,
            ttl: $ttl
        );

        $this->cache->set($cacheItem);
    }

    private function loadFrameworkConfig(): array
    {
        return [
            'cache_enabled' => $this->environment->getBool('CACHE_ENABLED', true),
            'debug_mode' => $this->environment->getBool('APP_DEBUG', false),
            'app_env' => $this->environment->get('APP_ENV', 'production'),
            'session_lifetime' => $this->environment->getInt('SESSION_LIFETIME', 7200),
            'cache_driver' => $this->environment->get('CACHE_DRIVER', 'file')
        ];
    }

    private function loadEnvironmentVariables(): array
    {
        // Only cache non-sensitive environment variables
        return [
            'app_name' => $this->environment->get('APP_NAME', 'Framework'),
            'app_url' => $this->environment->get('APP_URL', 'http://localhost'),
            'app_timezone' => $this->environment->get('APP_TIMEZONE', 'UTC'),
            'cache_prefix' => $this->environment->get('CACHE_PREFIX', 'app_')
        ];
    }

    protected function getMetadata(): array
    {
        return [
            'routes_count' => count($this->compiledRoutes->getStaticRoutes()) +
                             count($this->compiledRoutes->getDynamicRoutes()),
            'config_keys' => 5,
            'env_vars' => 4
        ];
    }

    public function getEstimatedDuration(): int
    {
        return 2; // Critical path should be very fast (2 seconds)
    }
}
