<?php

declare(strict_types=1);

namespace App\Framework\Database\Cache;

use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Database\EntityManager;

/**
 * Cache warmup strategies for preloading frequently accessed data
 */
final class CacheWarmupStrategy
{
    public function __construct(
        private readonly EntityManager $entityManager,
        private readonly EntityCacheManager $cacheManager
    ) {
    }

    /**
     * Warm up cache with commonly accessed entities
     */
    public function warmUpEntities(array $warmupStrategies): array
    {
        $results = [];

        foreach ($warmupStrategies as $entityClass => $strategy) {
            $results[$entityClass] = $this->executeWarmupStrategy($entityClass, $strategy);
        }

        return $results;
    }

    /**
     * Execute specific warmup strategy for entity class
     */
    private function executeWarmupStrategy(string $entityClass, array $strategy): array
    {
        $strategyType = $strategy['type'] ?? 'recent';
        $limit = $strategy['limit'] ?? 100;
        $ttl = isset($strategy['ttl']) ? Duration::fromSeconds($strategy['ttl']) : null;

        return match ($strategyType) {
            'recent' => $this->warmUpRecentEntities($entityClass, $limit, $ttl),
            'popular' => $this->warmUpPopularEntities($entityClass, $limit, $ttl),
            'critical' => $this->warmUpCriticalEntities($entityClass, $strategy['ids'] ?? [], $ttl),
            'all' => $this->warmUpAllEntities($entityClass, $limit, $ttl),
            default => ['status' => 'unknown_strategy', 'warmed' => 0]
        };
    }

    /**
     * Warm up recently created/updated entities
     */
    private function warmUpRecentEntities(string $entityClass, int $limit, ?Duration $ttl): array
    {
        try {
            // Load recent entities (assuming there's a created_at or updated_at field)
            $entities = $this->entityManager->findBy(
                $entityClass,
                [],
                ['created_at' => 'DESC'],
                $limit
            );

            $warmedCount = 0;
            foreach ($entities as $entity) {
                if ($this->cacheEntity($entity, $ttl)) {
                    $warmedCount++;
                }
            }

            return [
                'status' => 'success',
                'warmed' => $warmedCount,
                'total' => count($entities),
            ];

        } catch (\Throwable $e) {
            return [
                'status' => 'error',
                'error' => $e->getMessage(),
                'warmed' => 0,
            ];
        }
    }

    /**
     * Warm up popular entities (most accessed)
     */
    private function warmUpPopularEntities(string $entityClass, int $limit, ?Duration $ttl): array
    {
        try {
            // This would require access statistics - simplified implementation
            $entities = $this->entityManager->findBy(
                $entityClass,
                [],
                null,
                $limit
            );

            $warmedCount = 0;
            foreach ($entities as $entity) {
                if ($this->cacheEntity($entity, $ttl)) {
                    $warmedCount++;
                }
            }

            return [
                'status' => 'success',
                'warmed' => $warmedCount,
                'total' => count($entities),
            ];

        } catch (\Throwable $e) {
            return [
                'status' => 'error',
                'error' => $e->getMessage(),
                'warmed' => 0,
            ];
        }
    }

    /**
     * Warm up specific critical entities by ID
     */
    private function warmUpCriticalEntities(string $entityClass, array $entityIds, ?Duration $ttl): array
    {
        if (empty($entityIds)) {
            return ['status' => 'success', 'warmed' => 0, 'total' => 0];
        }

        $warmedCount = 0;
        $errorCount = 0;

        foreach ($entityIds as $entityId) {
            try {
                $entity = $this->entityManager->find($entityClass, $entityId);
                if ($entity !== null && $this->cacheEntity($entity, $ttl)) {
                    $warmedCount++;
                }
            } catch (\Throwable $e) {
                $errorCount++;
            }
        }

        return [
            'status' => $errorCount > 0 ? 'partial' : 'success',
            'warmed' => $warmedCount,
            'errors' => $errorCount,
            'total' => count($entityIds),
        ];
    }

    /**
     * Warm up all entities (dangerous for large tables)
     */
    private function warmUpAllEntities(string $entityClass, int $limit, ?Duration $ttl): array
    {
        try {
            $entities = $this->entityManager->findBy($entityClass, [], null, $limit);

            $warmedCount = 0;
            foreach ($entities as $entity) {
                if ($this->cacheEntity($entity, $ttl)) {
                    $warmedCount++;
                }
            }

            return [
                'status' => 'success',
                'warmed' => $warmedCount,
                'total' => count($entities),
            ];

        } catch (\Throwable $e) {
            return [
                'status' => 'error',
                'error' => $e->getMessage(),
                'warmed' => 0,
            ];
        }
    }

    /**
     * Cache a single entity
     */
    private function cacheEntity(object $entity, ?Duration $ttl): bool
    {
        try {
            $this->cacheManager->cacheEntity($entity);

            return true;
        } catch (\Throwable) {
            return false;
        }
    }

    /**
     * Get default warmup strategies for common entity types
     */
    public static function getDefaultStrategies(): array
    {
        return [
            'User' => [
                'type' => 'recent',
                'limit' => 50,
                'ttl' => 1800, // 30 minutes
            ],
            'Config' => [
                'type' => 'all',
                'limit' => 500,
                'ttl' => 86400, // 24 hours
            ],
            'Translation' => [
                'type' => 'all',
                'limit' => 1000,
                'ttl' => 86400, // 24 hours
            ],
            'Product' => [
                'type' => 'popular',
                'limit' => 200,
                'ttl' => 3600, // 1 hour
            ],
            'Category' => [
                'type' => 'all',
                'limit' => 100,
                'ttl' => 7200, // 2 hours
            ],
        ];
    }

    /**
     * Create warmup strategy for specific entity IDs
     */
    public static function createCriticalStrategy(array $entityIds, int $ttlSeconds = 3600): array
    {
        return [
            'type' => 'critical',
            'ids' => $entityIds,
            'ttl' => $ttlSeconds,
        ];
    }
}
