<?php

namespace App\Framework\Cache\Strategies;

use App\Framework\Cache\CacheKey;
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Core\ValueObjects\Timestamp;

/**
 * Heat map entry for tracking cache key usage
 */
final class HeatMapEntry
{
    /** @var array<array{timestamp: Timestamp, is_hit: bool, retrieval_time: ?float}> */
    private array $accesses = [];

    private int $totalHits = 0;

    private int $totalMisses = 0;

    private float $totalRetrievalTime = 0.0;

    private int $retrievalTimeCount = 0;

    public function __construct(
        private readonly CacheKey $key
    ) {}

    public function recordAccess(bool $isHit, ?Duration $retrievalTime = null): void
    {
        $this->accesses[] = [
            'timestamp' => Timestamp::now(),
            'is_hit' => $isHit,
            'retrieval_time' => $retrievalTime?->toSeconds(),
        ];

        if ($isHit) {
            $this->totalHits++;
        } else {
            $this->totalMisses++;
        }

        if ($retrievalTime !== null) {
            $this->totalRetrievalTime += $retrievalTime->toSeconds();
            $this->retrievalTimeCount++;
        }

        // Keep only recent data to prevent memory bloat
        $cutoff = Timestamp::now()->subtract(Duration::fromHours(48)); // Keep 48 hours
        $this->accesses = array_filter(
            $this->accesses,
            fn($access) => $access['timestamp']->isAfter($cutoff)
        );
    }

    public function getRecentAccesses(Timestamp $since): array
    {
        return array_filter(
            $this->accesses,
            fn($access) => $access['timestamp']->isAfter($since)
        );
    }

    public function getHitRate(): float
    {
        $total = $this->totalHits + $this->totalMisses;

        return $total > 0 ? ($this->totalHits / $total) : 0.0;
    }

    public function getAverageRetrievalTime(): float
    {
        return $this->retrievalTimeCount > 0 ? ($this->totalRetrievalTime / $this->retrievalTimeCount) : 0.0;
    }

    public function getTotalAccesses(): int
    {
        return count($this->accesses);
    }

    public function getLastAccessTime(): ?Timestamp
    {
        if (empty($this->accesses)) {
            return null;
        }

        return end($this->accesses)['timestamp'];
    }

    public function getKey(): CacheKey
    {
        return $this->key;
    }
}
