<?php

declare(strict_types=1);

namespace App\Services\EarlyGrowth;

use App\Models\Artwork;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;

/**
 * GridFiller
 *
 * Ensures that browse / discover grids never appear half-empty.
 * When real results fall below the configured minimum, it backfills
 * with real trending artworks from the general pool.
 *
 * Rules (per spec):
 *  - Fill only the visible first page — never mix page-number scopes.
 *  - Filler is always real content (no fake items).
 *  - The original total is not reduced (pagination links stay stable).
 *  - Content is not labelled as "filler" in the UI — it is just valid content.
 */
final class GridFiller
{
    /**
     * Ensure a LengthAwarePaginator contains at least $minimum items on page 1.
     * Returns the original paginator unchanged when:
     *  - EGS is disabled
     *  - Page is > 1
     *  - Real result count already meets the minimum
     */
    public function fill(
        LengthAwarePaginator $results,
        int $minimum = 0,
        int $page    = 1,
    ): LengthAwarePaginator {
        if (! EarlyGrowth::gridFillerEnabled() || $page > 1) {
            return $results;
        }

        $minimum = $minimum > 0
            ? $minimum
            : (int) config('early_growth.grid_min_results', 12);

        $items = $results->getCollection();
        $count = $items->count();

        if ($count >= $minimum) {
            return $results;
        }

        $needed  = $minimum - $count;
        $exclude = $items->pluck('id')->all();
        $filler  = $this->fetchTrendingFiller($needed + 6, $exclude)->take($needed);

        $merged = $items
            ->concat($filler)
            ->unique('id')
            ->values();

        return new LengthAwarePaginator(
            $merged->all(),
            max((int) $results->total(), $merged->count()), // never shrink reported total
            $results->perPage(),
            $page,
            [
                'path'     => $results->path(),
                'pageName' => $results->getPageName(),
            ]
        );
    }

    /**
     * Fill a plain Collection (for non-paginated grids like homepage sections).
     */
    public function fillCollection(Collection $items, int $minimum = 0): Collection
    {
        if (! EarlyGrowth::gridFillerEnabled()) {
            return $items;
        }

        $minimum = $minimum > 0
            ? $minimum
            : (int) config('early_growth.grid_min_results', 12);

        if ($items->count() >= $minimum) {
            return $items;
        }

        $needed  = $minimum - $items->count();
        $exclude = $items->pluck('id')->all();
        $filler  = $this->fetchTrendingFiller($needed + 6, $exclude)->take($needed);

        return $items->concat($filler)->unique('id')->values();
    }

    // ─── Private ─────────────────────────────────────────────────────────────

    /**
     * Pull high-ranking artworks as grid filler.
     * Cache key includes an exclude-hash so different grids get distinct content.
     */
    private function fetchTrendingFiller(int $limit, array $excludeIds): Collection
    {
        $ttl      = (int) config('early_growth.cache_ttl.feed_blend', 300);
        $excludeHash = md5(implode(',', array_slice(array_unique($excludeIds), 0, 50)));
        $cacheKey = "egs.grid_filler.{$excludeHash}.{$limit}";

        return Cache::remember($cacheKey, $ttl, function () use ($limit, $excludeIds): Collection {
            return Artwork::query()
                ->public()
                ->published()
                ->withoutMissingThumbnails()
                ->with([
                    'user:id,name,username',
                    'user.profile:user_id,avatar_hash',
                    'categories:id,name,slug,content_type_id,parent_id,sort_order',
                ])
                ->leftJoin('artwork_stats as _gf_stats', '_gf_stats.artwork_id', '=', 'artworks.id')
                ->select('artworks.*')
                ->when(! empty($excludeIds), fn ($q) => $q->whereNotIn('artworks.id', $excludeIds))
                ->orderByDesc('_gf_stats.ranking_score')
                ->limit($limit)
                ->get()
                ->values();
        });
    }
}
