<?php

namespace App\Services;

use Illuminate\Cache\CacheManager;
use Illuminate\Support\Collection;

class CacheService
{
    public function __construct(
        protected CacheManager $cache
    ) {}

    public function clearRepositoryCache(string $repository): void
    {
        $tag = $this->getRepositoryTag($repository);
        $this->cache->tags([$tag])->flush();
    }

    public function clearModelCache(string $model, ?int $modelId = null): void
    {
        $tag = $this->getModelTag($model);

        if ($modelId) {
            // Clear specific model cache and related caches
            $this->cache->tags([$tag])->flush();
        } else {
            // Clear all cache for this model type
            $this->cache->tags([$tag])->flush();
        }
    }

    public function warmUpCache(): void
    {
        $config = config('repositories.cache.warming.commands', []);

        foreach ($config as $command) {
            try {
                $this->executeWarmUpCommand($command);
            } catch (\Exception $e) {
                \Log::warning("Failed to warm up cache for command: {$command}", [
                    'error' => $e->getMessage(),
                ]);
            }
        }
    }

    public function getCacheStats(): array
    {
        return [
            'tags' => $this->getCacheTags(),
            'memory_usage' => memory_get_usage(true),
            'peak_memory' => memory_get_peak_usage(true),
        ];
    }

    public function clearAllRepositoryCache(): void
    {
        $tags = collect([
            'domains',
            'usernames',
        ])->map(fn ($tag) => $this->getFullTag($tag));

        $this->cache->tags($tags->toArray())->flush();
    }

    protected function getRepositoryTag(string $repository): string
    {
        return $this->getFullTag(config("repositories.cache.tags.{$repository}", $repository));
    }

    protected function getModelTag(string $model): string
    {
        $repository = strtolower(str_replace('App\\Models\\', '', $model));

        return $this->getRepositoryTag($repository);
    }

    protected function getFullTag(string $tag): string
    {
        $prefix = config('repositories.cache.prefix', 'repo');

        return "{$prefix}:{$tag}";
    }

    protected function executeWarmUpCommand(string $command): void
    {
        match ($command) {
            'domains:active' => $this->warmUpActiveDomains(),
            'usernames:active' => $this->warmUpActiveUsernames(),
            'domains:count' => $this->warmUpDomainCounts(),
            'usernames:count' => $this->warmUpUsernameCounts(),
            default => \Log::warning("Unknown warm-up command: {$command}"),
        };
    }

    protected function warmUpActiveDomains(): void
    {
        app(\App\Repositories\Domain\Read\DomainReadRepository::class)->findActive();
    }

    protected function warmUpActiveUsernames(): void
    {
        app(\App\Repositories\Username\Read\UsernameReadRepository::class)->findActive();
    }

    protected function warmUpDomainCounts(): void
    {
        $repo = app(\App\Repositories\Domain\Read\DomainReadRepository::class);
        $repo->countActive();
        $repo->countByProvider();
        $repo->countByType();
    }

    protected function warmUpUsernameCounts(): void
    {
        $repo = app(\App\Repositories\Username\Read\UsernameReadRepository::class);
        $repo->countActive();
        $repo->countByProvider();
        $repo->countByType();
    }

    protected function getCacheTags(): Collection
    {
        return collect(config('repositories.cache.tags', []))->keys();
    }
}
