<?php

declare(strict_types=1);

use App\Framework\LiveComponents\Cache\CacheMetricsCollector;
use App\Framework\LiveComponents\Cache\CacheType;

describe('CacheMetricsCollector', function () {
    it('initializes with empty metrics for all cache types', function () {
        $collector = new CacheMetricsCollector();

        $stateMetrics = $collector->getMetrics(CacheType::STATE);
        $slotMetrics = $collector->getMetrics(CacheType::SLOT);
        $templateMetrics = $collector->getMetrics(CacheType::TEMPLATE);

        expect($stateMetrics->hits)->toBe(0)
            ->and($slotMetrics->hits)->toBe(0)
            ->and($templateMetrics->hits)->toBe(0);
    });

    it('records hits for specific cache type', function () {
        $collector = new CacheMetricsCollector();

        $collector->recordHit(CacheType::STATE, 0.5);
        $collector->recordHit(CacheType::STATE, 0.6);

        $metrics = $collector->getMetrics(CacheType::STATE);

        expect($metrics->hits)->toBe(2)
            ->and($metrics->misses)->toBe(0);
    });

    it('records misses for specific cache type', function () {
        $collector = new CacheMetricsCollector();

        $collector->recordMiss(CacheType::SLOT, 1.0);
        $collector->recordMiss(CacheType::SLOT, 1.2);

        $metrics = $collector->getMetrics(CacheType::SLOT);

        expect($metrics->hits)->toBe(0)
            ->and($metrics->misses)->toBe(2);
    });

    it('records invalidations for specific cache type', function () {
        $collector = new CacheMetricsCollector();

        $collector->recordInvalidation(CacheType::TEMPLATE);
        $collector->recordInvalidation(CacheType::TEMPLATE);

        $metrics = $collector->getMetrics(CacheType::TEMPLATE);

        expect($metrics->invalidations)->toBe(2);
    });

    it('updates cache size for specific cache type', function () {
        $collector = new CacheMetricsCollector();

        $collector->updateSize(CacheType::STATE, 150);

        $metrics = $collector->getMetrics(CacheType::STATE);

        expect($metrics->totalSize)->toBe(150);
    });

    it('maintains separate metrics for different cache types', function () {
        $collector = new CacheMetricsCollector();

        $collector->recordHit(CacheType::STATE, 0.5);
        $collector->recordMiss(CacheType::SLOT, 1.0);
        $collector->recordInvalidation(CacheType::TEMPLATE);

        expect($collector->getMetrics(CacheType::STATE)->hits)->toBe(1)
            ->and($collector->getMetrics(CacheType::SLOT)->misses)->toBe(1)
            ->and($collector->getMetrics(CacheType::TEMPLATE)->invalidations)->toBe(1);
    });

    it('returns all metrics', function () {
        $collector = new CacheMetricsCollector();

        $collector->recordHit(CacheType::STATE, 0.5);
        $collector->recordHit(CacheType::SLOT, 0.6);

        $allMetrics = $collector->getAllMetrics();

        expect($allMetrics)->toBeArray()
            ->and($allMetrics)->toHaveKey('state')
            ->and($allMetrics)->toHaveKey('slot')
            ->and($allMetrics)->toHaveKey('template');
    });

    it('calculates aggregate metrics across all caches', function () {
        $collector = new CacheMetricsCollector();

        // State: 2 hits
        $collector->recordHit(CacheType::STATE, 0.5);
        $collector->recordHit(CacheType::STATE, 0.6);

        // Slot: 1 hit, 1 miss
        $collector->recordHit(CacheType::SLOT, 0.7);
        $collector->recordMiss(CacheType::SLOT, 1.0);

        // Template: 1 miss
        $collector->recordMiss(CacheType::TEMPLATE, 1.2);

        $aggregate = $collector->getAggregateMetrics();

        expect($aggregate->cacheType)->toBe(CacheType::MERGED)
            ->and($aggregate->hits)->toBe(3)
            ->and($aggregate->misses)->toBe(2)
            ->and($aggregate->getTotalOperations())->toBe(5);
    });

    it('generates comprehensive summary', function () {
        $collector = new CacheMetricsCollector();

        $collector->recordHit(CacheType::STATE, 0.5);
        $collector->recordMiss(CacheType::SLOT, 1.0);

        $summary = $collector->getSummary();

        expect($summary)->toHaveKey('overall')
            ->and($summary)->toHaveKey('by_type')
            ->and($summary)->toHaveKey('performance_assessment')
            ->and($summary['by_type'])->toHaveKey('state')
            ->and($summary['by_type'])->toHaveKey('slot')
            ->and($summary['by_type'])->toHaveKey('template');
    });

    it('assesses performance against targets', function () {
        $collector = new CacheMetricsCollector();

        // State: 80% hit rate (target: 70%)
        for ($i = 0; $i < 8; $i++) {
            $collector->recordHit(CacheType::STATE, 0.5);
        }
        for ($i = 0; $i < 2; $i++) {
            $collector->recordMiss(CacheType::STATE, 1.0);
        }

        $assessment = $collector->assessPerformance();

        expect($assessment['state_cache']['meets_target'])->toBeTrue()
            ->and($assessment['state_cache']['grade'])->toBe('B');
    });

    it('detects performance issues when targets not met', function () {
        $collector = new CacheMetricsCollector();

        // State: 50% hit rate (below 70% target)
        $collector->recordHit(CacheType::STATE, 0.5);
        $collector->recordMiss(CacheType::STATE, 1.0);

        expect($collector->hasPerformanceIssues())->toBeTrue();
    });

    it('generates performance warnings for underperforming caches', function () {
        $collector = new CacheMetricsCollector();

        // State: 50% hit rate (below 70% target)
        $collector->recordHit(CacheType::STATE, 0.5);
        $collector->recordMiss(CacheType::STATE, 1.0);

        $warnings = $collector->getPerformanceWarnings();

        expect($warnings)->toBeArray()
            ->and($warnings)->not->toBeEmpty()
            ->and($warnings[0])->toContain('State cache hit rate');
    });

    it('returns no warnings when all caches meet targets', function () {
        $collector = new CacheMetricsCollector();

        // State: 90% hit rate (exceeds 70% target)
        for ($i = 0; $i < 9; $i++) {
            $collector->recordHit(CacheType::STATE, 0.5);
        }
        $collector->recordMiss(CacheType::STATE, 1.0);

        // Slot: 80% hit rate (exceeds 60% target)
        for ($i = 0; $i < 8; $i++) {
            $collector->recordHit(CacheType::SLOT, 0.5);
        }
        for ($i = 0; $i < 2; $i++) {
            $collector->recordMiss(CacheType::SLOT, 1.0);
        }

        // Template: 90% hit rate (exceeds 80% target)
        for ($i = 0; $i < 9; $i++) {
            $collector->recordHit(CacheType::TEMPLATE, 0.5);
        }
        $collector->recordMiss(CacheType::TEMPLATE, 1.0);

        expect($collector->hasPerformanceIssues())->toBeFalse()
            ->and($collector->getPerformanceWarnings())->toBeEmpty();
    });

    it('exports metrics with timestamp', function () {
        $collector = new CacheMetricsCollector();

        $collector->recordHit(CacheType::STATE, 0.5);

        $export = $collector->export();

        expect($export)->toHaveKey('timestamp')
            ->and($export)->toHaveKey('metrics')
            ->and($export['timestamp'])->toBeInt();
    });

    it('resets all metrics', function () {
        $collector = new CacheMetricsCollector();

        $collector->recordHit(CacheType::STATE, 0.5);
        $collector->recordHit(CacheType::SLOT, 0.6);
        $collector->recordHit(CacheType::TEMPLATE, 0.7);

        $collector->reset();

        expect($collector->getMetrics(CacheType::STATE)->hits)->toBe(0)
            ->and($collector->getMetrics(CacheType::SLOT)->hits)->toBe(0)
            ->and($collector->getMetrics(CacheType::TEMPLATE)->hits)->toBe(0);
    });
});
