<?php

namespace App\Support;

use App\Models\Campaign;
use App\Models\ProviderOffer;
use Illuminate\Database\Eloquent\Model;

class OfferCurator
{
    /**
     * Weighted score used to rank offers against each other. Reward points
     * and payout are the primary signal; observed click popularity (from our
     * own site's offerwall_clicks tracking) is a secondary tiebreaker so
     * genuinely popular offers can outrank a slightly higher-paying one.
     */
    public function score(Model $offer): float
    {
        $reward = (float) ($offer->reward_points ?? 0);
        $payout = (float) ($offer->payout ?? 0);
        $clicks = (int) ($offer->clicks_count ?? 0);

        return $reward + ($payout * coins_per_usd()) + ($clicks * 5);
    }

    /**
     * Re-flag hot/featured offers. When $offerwallId is given, only that
     * offerwall's offers are re-scored (used right after a provider sync).
     * Rows with curation_locked = true are left untouched. Automatic callers
     * (sync, the scheduled command) respect the curation_auto_enabled
     * setting; pass $force = true for an explicit admin-triggered run.
     */
    public function curate(?int $offerwallId = null, bool $force = false): array
    {
        $summary = ['hot' => 0, 'featured' => 0, 'cleared' => 0];

        if (!$force && !site_bool('curation_auto_enabled', true)) {
            return $summary;
        }

        $summary = $this->curateProviderOffers($offerwallId, $summary);
        $summary = $this->curateCampaigns($offerwallId, $summary);

        return $summary;
    }

    private function curateProviderOffers(?int $offerwallId, array $summary): array
    {
        $query = ProviderOffer::where('is_active', true)
            ->where('curation_locked', false)
            ->withCount('clicks');

        if ($offerwallId) {
            $query->where('offerwall_id', $offerwallId);
        }

        foreach ($query->get()->groupBy('category') as $categoryOffers) {
            $summary = $this->applyCuration($categoryOffers, $summary, 'is_featured');
        }

        return $summary;
    }

    private function curateCampaigns(?int $offerwallId, array $summary): array
    {
        $query = Campaign::where('status', 'active')
            ->where('curation_locked', false)
            ->withCount('clicks');

        if ($offerwallId) {
            $query->where('offerwall_id', $offerwallId);
        }

        foreach ($query->get()->groupBy('category') as $categoryCampaigns) {
            $summary = $this->applyCuration($categoryCampaigns, $summary, 'featured');
        }

        return $summary;
    }

    private function applyCuration($offers, array $summary, string $featuredField): array
    {
        $hotCount = max(0, (int) site_setting('curation_hot_count', 6));
        $featuredMinReward = (float) site_setting('curation_featured_min_reward', 500);

        $ranked = $offers->sortByDesc(fn ($offer) => $this->score($offer))->values();
        $hotIds = $ranked->take($hotCount)->pluck('id')->all();

        foreach ($ranked as $offer) {
            $shouldBeHot = in_array($offer->id, $hotIds, true);
            $shouldBeFeatured = (float) $offer->reward_points >= $featuredMinReward;

            if ($offer->is_hot != $shouldBeHot || $offer->{$featuredField} != $shouldBeFeatured) {
                $offer->update(['is_hot' => $shouldBeHot, $featuredField => $shouldBeFeatured]);

                if ($shouldBeHot) {
                    $summary['hot']++;
                } elseif ($shouldBeFeatured) {
                    $summary['featured']++;
                } else {
                    $summary['cleared']++;
                }
            }
        }

        return $summary;
    }
}
