<?php

declare(strict_types=1);

namespace App\Framework\LiveComponents\Cache;

use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\LiveComponents\ValueObjects\ComponentState;

/**
 * Metrics-Aware Cache Invalidation Strategy Decorator
 *
 * Wraps CacheInvalidationStrategy to add automatic invalidation metrics collection.
 *
 * Tracks:
 * - Invalidation counts per cache type
 * - Bulk invalidation operations
 * - Clear-all operations
 */
final readonly class MetricsAwareCacheInvalidationStrategy
{
    public function __construct(
        private CacheInvalidationStrategy $strategy,
        private CacheMetricsCollector $metricsCollector
    ) {
    }

    public function invalidateComponent(ComponentId $componentId): CacheInvalidationResult
    {
        $result = $this->strategy->invalidateComponent($componentId);

        if ($result->success) {
            foreach ($result->invalidated as $cacheType) {
                $this->recordInvalidation($cacheType);
            }
        }

        return $result;
    }

    public function invalidateComponentSlots(ComponentId $componentId): CacheInvalidationResult
    {
        $result = $this->strategy->invalidateComponentSlots($componentId);

        if ($result->success) {
            $this->metricsCollector->recordInvalidation(CacheType::SLOT);
        }

        return $result;
    }

    public function invalidateSlot(ComponentId $componentId, string $slotName): CacheInvalidationResult
    {
        $result = $this->strategy->invalidateSlot($componentId, $slotName);

        if ($result->success) {
            $this->metricsCollector->recordInvalidation(CacheType::SLOT);
        }

        return $result;
    }

    public function invalidateComponentType(string $componentType): CacheInvalidationResult
    {
        $result = $this->strategy->invalidateComponentType($componentType);

        if ($result->success) {
            $this->metricsCollector->recordInvalidation(CacheType::TEMPLATE);
        }

        return $result;
    }

    public function invalidateVariant(string $componentType, string $variant): CacheInvalidationResult
    {
        $result = $this->strategy->invalidateVariant($componentType, $variant);

        if ($result->success) {
            $this->metricsCollector->recordInvalidation(CacheType::TEMPLATE);
        }

        return $result;
    }

    public function invalidateOnStateChange(
        ComponentId $componentId,
        ComponentState $oldState,
        ComponentState $newState
    ): CacheInvalidationResult {
        $result = $this->strategy->invalidateOnStateChange($componentId, $oldState, $newState);

        if ($result->success) {
            foreach ($result->invalidated as $cacheType) {
                $this->recordInvalidation($cacheType);
            }
        }

        return $result;
    }

    public function clearAll(): CacheInvalidationResult
    {
        $result = $this->strategy->clearAll();

        if ($result->success) {
            // Record invalidation for all cache types
            $this->metricsCollector->recordInvalidation(CacheType::STATE);
            $this->metricsCollector->recordInvalidation(CacheType::SLOT);
            $this->metricsCollector->recordInvalidation(CacheType::TEMPLATE);
        }

        return $result;
    }

    public function invalidateBulk(array $componentIds): CacheInvalidationResult
    {
        $result = $this->strategy->invalidateBulk($componentIds);

        if ($result->success) {
            // Each component invalidates state and slots
            $count = count($componentIds);
            for ($i = 0; $i < $count; $i++) {
                $this->metricsCollector->recordInvalidation(CacheType::STATE);
                $this->metricsCollector->recordInvalidation(CacheType::SLOT);
            }
        }

        return $result;
    }

    public function getStats(): array
    {
        return $this->strategy->getStats();
    }

    /**
     * Record invalidation based on cache type string
     */
    private function recordInvalidation(string $cacheTypeString): void
    {
        $cacheType = match ($cacheTypeString) {
            'state' => CacheType::STATE,
            'slots', 'slot' => CacheType::SLOT,
            'templates', 'template' => CacheType::TEMPLATE,
            default => null
        };

        if ($cacheType !== null) {
            $this->metricsCollector->recordInvalidation($cacheType);
        }
    }
}
