<?php

namespace App\Services;

use App\Models\MemeMedia;
use Illuminate\Contracts\Pagination\CursorPaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Collection as SupportCollection;
use Illuminate\Support\Facades\Cache;

class MemeMediaService
{
    /**
     * Search memes with optional query and pagination
     */
    public function searchMemes(?string $search = null, int $perPage = 24): CursorPaginator
    {
        $query = $this->buildSearchQuery($search);

        return $query->cursorPaginate($perPage);
    }

    /**
     * Get popular keywords for filtering
     */
    public function getPopularKeywords(int $limit = 20): SupportCollection
    {
        $cacheKey = "popular_keywords_limit_{$limit}";

        return Cache::remember($cacheKey, 60 * 60 * 24, function () use ($limit) {
            return MemeMedia::where('is_enabled', true)
                ->get()
                ->pluck('keywords')
                ->flatten()
                ->countBy()
                ->sort()
                ->reverse()
                ->take($limit)
                ->keys();
        });
    }

    /**
     * Get available meme types for filtering
     */
    public function getAvailableTypes(): SupportCollection
    {
        return MemeMedia::where('is_enabled', true)
            ->distinct()
            ->pluck('type')
            ->filter();
    }

    /**
     * Find meme by slug
     */
    public function findBySlug(string $slug): MemeMedia
    {
        return MemeMedia::where('slug', $slug)
            ->where('is_enabled', true)
            ->firstOrFail();
    }

    /**
     * Find meme by hashids
     */
    public function findByHashIds(string $ids): MemeMedia
    {
        $memeId = hashids_decode($ids);

        if (! $memeId) {
            throw new ModelNotFoundException('Meme not found');
        }

        return MemeMedia::where('id', $memeId)
            ->where('is_enabled', true)
            ->firstOrFail();
    }

    /**
     * Get related memes based on keywords
     */
    public function getRelatedMemes(MemeMedia $meme, int $limit = 6): Collection
    {
        $relatedMemes = MemeMedia::where('is_enabled', true)
            ->where('id', '!=', $meme->id)
            ->where(function ($query) use ($meme) {
                if ($meme->keywords) {
                    foreach ($meme->keywords as $keyword) {
                        $query->orWhereJsonContains('keywords', $keyword)
                            ->orWhereJsonContains('action_keywords', $keyword)
                            ->orWhereJsonContains('emotion_keywords', $keyword)
                            ->orWhereJsonContains('misc_keywords', $keyword);
                    }
                }
            })
            ->limit($limit)
            ->get();

        // If we have less than the desired limit, fill up with random ones
        if ($relatedMemes->count() < $limit) {
            $excludeIds = $relatedMemes->pluck('id')->push($meme->id)->toArray();
            $needed = $limit - $relatedMemes->count();

            $randomMemes = $this->fillWithRandomMemes($relatedMemes, $limit, $excludeIds);
            $relatedMemes = $relatedMemes->merge($randomMemes);
        }

        return $relatedMemes;
    }

    /**
     * Fill collection with random memes up to target count
     */
    public function fillWithRandomMemes(Collection $existing, int $targetCount, array $excludeIds): Collection
    {
        $needed = $targetCount - $existing->count();

        if ($needed <= 0) {
            return collect();
        }

        return MemeMedia::where('is_enabled', true)
            ->whereNotIn('id', $excludeIds)
            ->inRandomOrder()
            ->limit($needed)
            ->get();
    }

    /**
     * Build search query with keyword matching
     */
    private function buildSearchQuery(?string $search = null): Builder
    {
        $query = $this->getEnabledMemesQuery();

        if ($search) {
            $query->where(function ($q) use ($search) {
                $q->where('name', 'ilike', "%{$search}%")
                    ->orWhere('description', 'ilike', "%{$search}%")
                    ->orWhereJsonContains('keywords', $search)
                    ->orWhereJsonContains('action_keywords', $search)
                    ->orWhereJsonContains('emotion_keywords', $search)
                    ->orWhereJsonContains('misc_keywords', $search);
            });
        }

        return $query;
    }

    /**
     * Get all enabled memes for sitemap generation
     */
    public function getAllEnabledMemes(): Collection
    {
        return MemeMedia::where('is_enabled', true)
            ->orderBy('updated_at', 'desc')
            ->get();
    }

    /**
     * Get base query for enabled memes
     */
    private function getEnabledMemesQuery(): Builder
    {
        return MemeMedia::query()
            ->where('is_enabled', true)
            ->orderBy('id', 'desc');
    }
}
