<?php

declare(strict_types=1);

namespace App\Services\EarlyGrowth;

use App\Services\EarlyGrowth\SpotlightEngineInterface;
use Illuminate\Pagination\LengthAwarePaginator;

/**
 * FeedBlender
 *
 * Blends real fresh uploads with curated older content and spotlight picks
 * to make early-stage feeds feel alive and diverse without faking engagement.
 *
 * Rules:
 *  - ONLY applied to page 1 — deeper pages use the real feed untouched.
 *  - No fake artworks, timestamps, or metrics.
 *  - Duplicates removed before merging.
 *  - The original paginator's total / path / page-name are preserved so
 *    pagination links and SEO canonical/prev/next remain correct.
 *
 * Mode blend ratios are defined in config/early_growth.php:
 *   light      → 60% fresh / 25% curated / 15% spotlight
 *   aggressive → 30% fresh / 50% curated / 20% spotlight
 */
final class FeedBlender
{
    public function __construct(
        private readonly SpotlightEngineInterface $spotlight,
    ) {}

    /**
     * Blend a LengthAwarePaginator of fresh artworks with curated and spotlight content.
     *
     * @param LengthAwarePaginator $freshResults  Original fresh-upload paginator
     * @param int                  $perPage        Items per page
     * @param int                  $page           Current page number
     * @return LengthAwarePaginator                Blended paginator (page 1) or original (page > 1)
     */
    public function blend(
        LengthAwarePaginator $freshResults,
        int $perPage = 24,
        int $page    = 1,
    ): LengthAwarePaginator {
        // Only blend on page 1; real pagination takes over for deeper pages
        if (! EarlyGrowth::enabled() || $page > 1) {
            return $freshResults;
        }

        $ratios = EarlyGrowth::blendRatios();

        if (($ratios['curated'] + $ratios['spotlight']) < 0.001) {
            // Mode is effectively "fresh only" — nothing to blend
            return $freshResults;
        }

        $fresh    = $freshResults->getCollection();
        $freshIds = $fresh->pluck('id')->toArray();

        // Calculate absolute item counts from ratios
        [$freshCount, $curatedCount, $spotlightCount] = $this->allocateCounts($ratios, $perPage);

        // Fetch sources — over-fetch to account for deduplication losses
        $curated = $this->spotlight
            ->getCurated($curatedCount + 6)
            ->filter(fn ($a) => ! in_array($a->id, $freshIds, true))
            ->take($curatedCount)
            ->values();

        $curatedIds = $curated->pluck('id')->toArray();

        $spotlightItems = $this->spotlight
            ->getSpotlight($spotlightCount + 6)
            ->filter(fn ($a) => ! in_array($a->id, $freshIds, true))
            ->filter(fn ($a) => ! in_array($a->id, $curatedIds, true))
            ->take($spotlightCount)
            ->values();

        // Compose blended page
        $blended = $fresh->take($freshCount)
            ->concat($curated)
            ->concat($spotlightItems)
            ->unique('id')
            ->values();

        // Pad back to $perPage with leftover fresh items if any source ran short
        if ($blended->count() < $perPage) {
            $usedIds = $blended->pluck('id')->toArray();
            $pad     = $fresh
                ->filter(fn ($a) => ! in_array($a->id, $usedIds, true))
                ->take($perPage - $blended->count());
            $blended = $blended->concat($pad)->unique('id')->values();
        }

        // Rebuild paginator preserving the real total so pagination links remain stable
        return new LengthAwarePaginator(
            $blended->take($perPage)->all(),
            $freshResults->total(),           // ← real total, not blended count
            $perPage,
            $page,
            [
                'path'     => $freshResults->path(),
                'pageName' => $freshResults->getPageName(),
            ]
        );
    }

    // ─── Private helpers ─────────────────────────────────────────────────────

    /**
     * Distribute $perPage slots across fresh / curated / spotlight.
     * Returns [freshCount, curatedCount, spotlightCount].
     */
    private function allocateCounts(array $ratios, int $perPage): array
    {
        $total   = max(0.001, ($ratios['fresh'] ?? 0) + ($ratios['curated'] ?? 0) + ($ratios['spotlight'] ?? 0));
        $freshN  = (int) round($perPage * ($ratios['fresh']     ?? 1.0) / $total);
        $curatedN = (int) round($perPage * ($ratios['curated']   ?? 0.0) / $total);
        $spotN   = $perPage - $freshN - $curatedN;

        return [max(0, $freshN), max(0, $curatedN), max(0, $spotN)];
    }
}
