<?php

declare(strict_types=1);

namespace App\Framework\Reflection\Strategies;

use App\Framework\DateTime\Clock;

/**
 * Memory-aware cache strategy with LRU eviction
 */
final class MemoryAwareCacheStrategy
{
    /**
     * @var array<string, int>
     */
    private array $accessTimes = [];

    private int $maxMemoryUsage;

    private int $maxEntries;

    public function __construct(
        private readonly Clock $clock,
        int $maxMemoryUsage = 10 * 1024 * 1024, // 10MB
        int $maxEntries = 1000
    ) {
        $this->maxMemoryUsage = $maxMemoryUsage;
        $this->maxEntries = $maxEntries;
    }

    /**
     * @param array<string, mixed> $cache
     */
    public function shouldEvict(array $cache, string $key): bool
    {
        // Track access time
        $this->accessTimes[$key] = $this->clock->time()->toTimestamp();

        // Check memory usage
        $memoryUsage = strlen(serialize($cache));
        if ($memoryUsage > $this->maxMemoryUsage) {
            return true;
        }

        // Check entry count
        if (count($cache) > $this->maxEntries) {
            return true;
        }

        return false;
    }

    /**
     * @return array<int, string>
     */
    public function getLeastRecentlyUsedKeys(int $count): array
    {
        asort($this->accessTimes);

        return array_slice(array_keys($this->accessTimes), 0, $count);
    }

    /**
     * @param array<string, mixed> $cache
     */
    public function evictLeastRecentlyUsed(array &$cache, int $count): void
    {
        $keysToEvict = $this->getLeastRecentlyUsedKeys($count);

        foreach ($keysToEvict as $key) {
            unset($cache[$key], $this->accessTimes[$key]);
        }
    }
}
