<?php

namespace App\Services\Contest;

use App\Enums\CoinMatterEnum;
use App\Enums\ContestStatusEnum;
use App\Enums\NotificationType;
use App\Enums\ParticipantStatusEnum;
use App\Events\CoinLogEvent;
use App\Models\Contest;
use App\Models\ContestWinner;
use Illuminate\Support\Facades\Notification;

class ContestWinnerService
{
    /**
     * Determine the winner of the contest based on the highest score.
     *
     * @param  \Illuminate\Database\Eloquent\Collection  $contest
     * @return \App\Models\ContestParticipant|null
     */
    public function determineWinner(Contest $contest)
    {
        $contest = tap($contest, function ($contest) {
            $contest->update([
                'status' => ContestStatusEnum::COMPLETED,
            ]);
        });

        $prizes = $contest->prizes()->orderBy('rank')->get();

        $participants = $contest->participants()
            ->where('status', ParticipantStatusEnum::SUBMITTED)
            ->orderByDesc('score', 'time_taken')
            ->limit(count($prizes))
            ->get();

        if ($participants->isEmpty()) {
            return null;
        }

        foreach ($participants as $index => $participant) {
            $coin_amount = $prizes[$index]->amount;
            ContestWinner::create([
                'contest_id' => $contest->id,
                'user_id' => $participant->user_id,
                'participant_id' => $participant->id,
                'prize_name' => $prizes[$index]->name,
                'prize_amount' => $coin_amount,
                'rank' => $prizes[$index]->rank,
            ]);

            $participant->user->increment('coins', $coin_amount);

            $participant->status = ParticipantStatusEnum::WON;
            $participant->save();

            event(new CoinLogEvent($participant->user, CoinMatterEnum::BALANCE_DEDUCT, $coin_amount, '+'));

            Notification::sendNow(
                $participant->user,
                new \App\Notifications\UserAutoNotification(
                    NotificationType::CONTEST_WINNER,
                    [
                        'coins' => $participant->prize->amount,
                    ])
            );
        }

        $contest->participants()
            ->where('status', ParticipantStatusEnum::SUBMITTED)
            ->whereNotIn('id', $participants->pluck('id'))
            ->update([
                'status' => ParticipantStatusEnum::LOST,
            ]);
    }
}
