<?php

namespace App\Repositories\Username\Read;

use App\enum\ProviderType;
use App\enum\UsernameType;
use App\Models\Username;
use App\Repositories\BaseRepository;
use Illuminate\Database\Eloquent\Collection;

class UsernameReadRepository extends BaseRepository
{
    protected function getCacheTag(): string
    {
        return 'usernames';
    }

    public function getModel(): string
    {
        return Username::class;
    }

    public function findActive(): Collection
    {
        $cacheKey = $this->getCacheKey('active');

        return $this->executeQuery(function () {
            $result = $this->query
                ->where('is_active', true)
                ->where(function ($query) {
                    $query->whereNull('starts_at')
                        ->orWhere('starts_at', '<=', now());
                })
                ->where(function ($query) {
                    $query->whereNull('ends_at')
                        ->orWhere('ends_at', '>=', now());
                })
                ->get();
            $this->resetQuery();

            return $result;
        }, $cacheKey, 1800); // 30 minutes
    }

    public function findActiveByType(?UsernameType $usernameType = null, ?ProviderType $providerType = null): array
    {
        $params = [
            'username_type' => $usernameType?->value,
            'provider_type' => $providerType?->value,
        ];
        $cacheKey = $this->getCacheKey('active_by_type', $params);

        return $this->executeQuery(function () use ($usernameType, $providerType) {
            $query = $this->query
                ->where('is_active', true)
                ->where(function ($query) {
                    $query->whereNull('starts_at')
                        ->orWhere('starts_at', '<=', now());
                })
                ->where(function ($query) {
                    $query->whereNull('ends_at')
                        ->orWhere('ends_at', '>=', now());
                });

            if ($usernameType) {
                $query->where('username_type', $usernameType->value);
            }

            if ($providerType) {
                $query->where('provider_type', $providerType->value);
            }

            $result = $query->pluck('username')->toArray();
            $this->resetQuery();

            return $result;
        }, $cacheKey, 1800); // 30 minutes
    }

    public function findActiveByProvider(ProviderType $providerType): Collection
    {
        $cacheKey = $this->getCacheKey('active_by_provider', ['provider' => $providerType->value]);

        return $this->executeQuery(function () use ($providerType) {
            $result = $this->query
                ->where('is_active', true)
                ->where('provider_type', $providerType->value)
                ->where(function ($query) {
                    $query->whereNull('starts_at')
                        ->orWhere('starts_at', '<=', now());
                })
                ->where(function ($query) {
                    $query->whereNull('ends_at')
                        ->orWhere('ends_at', '>=', now());
                })
                ->get();
            $this->resetQuery();

            return $result;
        }, $cacheKey, 1800);
    }

    public function findPublicActive(): Collection
    {
        $cacheKey = $this->getCacheKey('public_active');

        return $this->executeQuery(function () {
            $result = $this->query
                ->where('is_active', true)
                ->where('username_type', UsernameType::PUBLIC->value)
                ->where(function ($query) {
                    $query->whereNull('starts_at')
                        ->orWhere('starts_at', '<=', now());
                })
                ->where(function ($query) {
                    $query->whereNull('ends_at')
                        ->orWhere('ends_at', '>=', now());
                })
                ->get();
            $this->resetQuery();

            return $result;
        }, $cacheKey, 1800);
    }

    public function findPremiumActive(): Collection
    {
        $cacheKey = $this->getCacheKey('premium_active');

        return $this->executeQuery(function () {
            $result = $this->query
                ->where('is_active', true)
                ->where('username_type', UsernameType::PREMIUM->value)
                ->where(function ($query) {
                    $query->whereNull('starts_at')
                        ->orWhere('starts_at', '<=', now());
                })
                ->where(function ($query) {
                    $query->whereNull('ends_at')
                        ->orWhere('ends_at', '>=', now());
                })
                ->get();
            $this->resetQuery();

            return $result;
        }, $cacheKey, 1800);
    }

    public function findExpiringSoon(int $days = 7): Collection
    {
        $cacheKey = $this->getCacheKey('expiring_soon', ['days' => $days]);

        return $this->executeQuery(function () use ($days) {
            $result = $this->query
                ->where('is_active', true)
                ->whereNotNull('ends_at')
                ->where('ends_at', '<=', now()->addDays($days))
                ->where('ends_at', '>', now())
                ->orderBy('ends_at', 'asc')
                ->get();
            $this->resetQuery();

            return $result;
        }, $cacheKey, 900); // 15 minutes
    }

    public function findInactive(): Collection
    {
        $cacheKey = $this->getCacheKey('inactive');

        return $this->executeQuery(function () {
            $result = $this->query
                ->where('is_active', false)
                ->orWhere(function ($query) {
                    $query->whereNotNull('starts_at')
                        ->where('starts_at', '>', now());
                })
                ->orWhere(function ($query) {
                    $query->whereNotNull('ends_at')
                        ->where('ends_at', '<', now());
                })
                ->get();
            $this->resetQuery();

            return $result;
        }, $cacheKey, 1800);
    }

    public function findRecentlyUsed(int $hours = 24): Collection
    {
        $cacheKey = $this->getCacheKey('recently_used', ['hours' => $hours]);

        return $this->executeQuery(function () use ($hours) {
            $result = $this->query
                ->whereNotNull('last_used_at')
                ->where('last_used_at', '>=', now()->subHours($hours))
                ->orderBy('last_used_at', 'desc')
                ->get();
            $this->resetQuery();

            return $result;
        }, $cacheKey, 900); // 15 minutes
    }

    public function findByUsername(string $username): ?Username
    {
        $cacheKey = $this->getCacheKey('find_by_username', ['username' => $username]);

        return $this->executeQuery(function () use ($username) {
            $result = $this->query->where('username', $username)->first();
            $this->resetQuery();

            return $result;
        }, $cacheKey, 3600); // 1 hour
    }

    public function countActive(): int
    {
        $cacheKey = $this->getCacheKey('count_active');

        return $this->executeQuery(function () {
            $result = $this->query
                ->where('is_active', true)
                ->where(function ($query) {
                    $query->whereNull('starts_at')
                        ->orWhere('starts_at', '<=', now());
                })
                ->where(function ($query) {
                    $query->whereNull('ends_at')
                        ->orWhere('ends_at', '>=', now());
                })
                ->count();
            $this->resetQuery();

            return $result;
        }, $cacheKey, 600); // 10 minutes
    }

    public function countByProvider(): array
    {
        $cacheKey = $this->getCacheKey('count_by_provider');

        return $this->executeQuery(function () {
            $result = $this->query
                ->selectRaw('provider_type, COUNT(*) as count')
                ->groupBy('provider_type')
                ->pluck('count', 'provider_type')
                ->toArray();
            $this->resetQuery();

            return $result;
        }, $cacheKey, 1800);
    }

    public function countByType(): array
    {
        $cacheKey = $this->getCacheKey('count_by_type');

        return $this->executeQuery(function () {
            $result = $this->query
                ->selectRaw('username_type, COUNT(*) as count')
                ->groupBy('username_type')
                ->pluck('count', 'username_type')
                ->toArray();
            $this->resetQuery();

            return $result;
        }, $cacheKey, 1800);
    }

    public function findAvailableForUse(UsernameType $type, int $limit = 10): Collection
    {
        $cacheKey = $this->getCacheKey('available_for_use', [
            'type' => $type->value,
            'limit' => $limit,
        ]);

        return $this->executeQuery(function () use ($type, $limit) {
            $result = $this->query
                ->where('is_active', true)
                ->where('username_type', $type->value)
                ->where(function ($query) {
                    $query->whereNull('starts_at')
                        ->orWhere('starts_at', '<=', now());
                })
                ->where(function ($query) {
                    $query->whereNull('ends_at')
                        ->orWhere('ends_at', '>=', now());
                })
                ->orderBy('last_used_at', 'asc')
                ->limit($limit)
                ->get();
            $this->resetQuery();

            return $result;
        }, $cacheKey, 300); // 5 minutes
    }

    public function findUnused(int $days = 30): Collection
    {
        $cacheKey = $this->getCacheKey('unused', ['days' => $days]);

        return $this->executeQuery(function () {
            $result = $this->query
                ->where('is_active', true)
                ->where(function ($query) {
                    $query->whereNull('last_used_at')
                        ->orWhere('last_used_at', '<', now()->subDays($days));
                })
                ->orderBy('last_used_at', 'asc')
                ->get();
            $this->resetQuery();

            return $result;
        }, $cacheKey, 1800);
    }
}
