<?php

namespace App\Queries;

use App\Enums\GameStatus;
use App\Models\Game;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Cache;

class GameCatalogQuery
{
    private const CACHE_KEY = 'games.catalog.active.v2';

    private const CACHE_TTL_SECONDS = 3600;

    public function allActive(): Collection
    {
        $cached = Cache::get(self::CACHE_KEY);

        if ($this->isValidCollection($cached)) {
            return $cached;
        }

        if ($cached !== null) {
            Cache::forget(self::CACHE_KEY);
        }

        $games = $this->queryActiveGames();

        Cache::put(self::CACHE_KEY, $games, self::CACHE_TTL_SECONDS);

        return $games;
    }

    public function findActiveBySlug(string $slug): ?Game
    {
        return $this->allActive()->firstWhere('slug', $slug);
    }

    public function findActiveBySlugOrFail(string $slug): Game
    {
        $game = $this->findActiveBySlug($slug);

        if ($game === null) {
            abort(404);
        }

        return $game;
    }

    public function flush(): void
    {
        Cache::forget(self::CACHE_KEY);
        Cache::forget('games.catalog.active');
    }

    private function queryActiveGames(): Collection
    {
        return Game::query()
            ->where('status', GameStatus::Active)
            ->with([
                'translations',
                'platforms' => fn ($query) => $query->orderBy('sort_order'),
                'regions' => fn ($query) => $query->orderBy('sort_order'),
                'ranks' => fn ($query) => $query->orderBy('sort_order'),
                'roles' => fn ($query) => $query->orderBy('sort_order'),
                'characters' => fn ($query) => $query->orderBy('sort_order'),
            ])
            ->withCount('playerGameProfiles')
            ->orderBy('sort_order')
            ->orderBy('name')
            ->get();
    }

    private function isValidCollection(mixed $value): bool
    {
        if (! $value instanceof Collection) {
            return false;
        }

        foreach ($value as $item) {
            if (! $item instanceof Game) {
                return false;
            }
        }

        return true;
    }
}
