<?php

namespace App\Models;

use Exception;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;

class Prize extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'max_allowed_per_hour',
        'total_allocated_count'
    ];

    const DEFAULT_PRIZE_IDENTIFIER = 1;

    public static function findRandomPrize($uuid)
    {
        // store the identifiers that we need to ignore for the prizes
        $ignoreIds = [3];
        $mainPrizeIds = [3, 4, 5];

        // iterate through a loop to find the prizes
        $count = 1;
        $randomPrize = null;

        try {
            $lastPrizeDistributionId = PrizeDistributionConfiguration::findKeyValue('LastPrizeDistributedId');
            $defaultPrizeDistributedCount = (int) PrizeDistributionConfiguration::findKeyValue('DefaultPrizeDistributedCount');

            if ($defaultPrizeDistributedCount == 2) {
                PrizeDistributionConfiguration::setKeyValue('DefaultPrizeDistributedCount', 0);

                // find a random number
                $randomNumber = rand(1, 1000); // Generate a random number between 1 and 100
                $randomPrizeId = ($randomNumber % 2 === 0) ? self::DEFAULT_PRIZE_IDENTIFIER : 1;

                // return pen or notepad
                return Arr::only(Prize::whereIn('id', [$randomPrizeId])->first()->toArray(), ['id', 'name', 'title', 'description', 'degree', 'display_order']);
            }

            // increase the prize distribution count
            $defaultPrizeDistributedCount++;
            PrizeDistributionConfiguration::setKeyValue('DefaultPrizeDistributedCount', $defaultPrizeDistributedCount);

            while ($count <= 11) {
                Log::info('COUNT:' . $count);
                // find a random prize
                try {
                    // we need to give weight age to smaller prizes - we will see
                    if (in_array($lastPrizeDistributionId, $mainPrizeIds))
                        $ignoreIds = $mainPrizeIds;

                    $prizeObject = Prize::whereNotIn('id', $ignoreIds)->inRandomOrder()->first();
                    if ($prizeObject)
                        $randomPrize = $prizeObject->toArray();
                    else {
                        $randomPrize = null;
                        break;
                    }
                } catch (Exception $e) {
                    $randomPrize = null;
                    break;
                }

                Log::info('Checking for prize:' . $randomPrize['id']);

                // check if the last prize given is the same as the random prize - then we need to find another prize
                if ($randomPrize['id'] != $lastPrizeDistributionId) {
                    if ($randomPrize['total_allocated_count'] < $randomPrize['max_allowed_total']) {
                        // check if prize then we need to distribute it evenly spread over a period of 5 hours
                        // find the current count for this hour
                        $allocated_this_hour = PrizeDistribution::findTotalPrizeDistributedThisHourAndDay(
                            $randomPrize['id'],
                            config('app.selected_day')
                        );

                        // find the allowed per hour value for this prize
                        if ($allocated_this_hour >= $randomPrize['max_allowed_per_hour']) {
                            $ignoreIds[] = $randomPrize['id'];
                            Log::info('Prize Allocated this hour Count is greater:' . $randomPrize['id'] . ':' . config('app.selected_day'));
                        } else
                            break;
                    } else {
                        $ignoreIds[] = $randomPrize['id'];
                        Log::info('Prize Total Allocated Count is greater:' . $randomPrize['id']);
                    }
                } else {
                    $ignoreIds[] = $randomPrize['id'];
                    Log::info('Prize same as last distributed:' . $randomPrize['id']);
                }

                Log::info(json_encode($ignoreIds));
                $count++;
            }
        } catch (\Exception $ex) {
            dd($ignoreIds, $ex->getMessage());
        }

        if ($randomPrize)
            $finalPrize = Arr::only($randomPrize, ['id', 'name', 'title', 'description', 'degree', 'display_order']);
        else
            // we need to return the default prize - so that user has at-least one prize
            $finalPrize = Prize::whereIn('id', [self::DEFAULT_PRIZE_IDENTIFIER])->inRandomOrder()->first(['id', 'name', 'title', 'description', 'degree', 'display_order'])->toArray();

        Log::info(json_encode($finalPrize));

        // double check if we aren't giving another free spin to the user who already has got one
        if ($finalPrize['id'] == 6 && PrizeDistributionConfiguration::keyExists('FreeSpinCount:' . $uuid)) {
            // we need to give default prize
            return Arr::only(Prize::whereIn('id', [self::DEFAULT_PRIZE_IDENTIFIER])->inRandomOrder()->first()
                ->toArray(), ['id', 'name', 'title', 'description', 'degree', 'display_order']);
            PrizeDistributionConfiguration::where('key', 'FreeSpinCount:' . $uuid)->delete();
        }


        return $finalPrize;
    }

    public static function findRandomPrizeStimulator($day, &$logs)
    {
        // store the identifiers that we need to ignore for the prizes
        $ignoreIds = [];
        $mainPrizeIds = [3, 4, 5];

        // iterate through a loop to find the prizes
        $count = 1;
        $randomPrize = null;
        Log::info('Start Day:' . $day);

        try {
            $lastPrizeDistributionId = PrizeDistributionConfiguration::findKeyValue('LastPrizeDistributedId');
            $defaultPrizeDistributedCount = (int) PrizeDistributionConfiguration::findKeyValue('DefaultPrizeDistributedCount');

            Log::info('Last Prize Distributed:' . $lastPrizeDistributionId);

            if ($defaultPrizeDistributedCount == 2) {
                PrizeDistributionConfiguration::setKeyValue('DefaultPrizeDistributedCount', 0);
                // return pen
                return Arr::only(Prize::whereIn('id', [self::DEFAULT_PRIZE_IDENTIFIER])->inRandomOrder()->first()
                    ->toArray(), ['id', 'name', 'title', 'description', 'degree', 'display_order']);
            }

            // increase the prize distribution count
            $defaultPrizeDistributedCount++;
            PrizeDistributionConfiguration::setKeyValue('DefaultPrizeDistributedCount', $defaultPrizeDistributedCount);

            while ($count <= 11) {
                // find a random prize
                try {
                    // we need to give weight age to smaller prizes - we will see
                    if (in_array($lastPrizeDistributionId, $mainPrizeIds))
                        $ignoreIds = $mainPrizeIds;

                    $prizeObject = Prize::whereNotIn('id', $ignoreIds)->inRandomOrder()->first();
                    if ($prizeObject)
                        $randomPrize = $prizeObject->toArray();
                    else {
                        $randomPrize = null;
                        break;
                    }
                } catch (Exception $e) {
                    $randomPrize = null;
                    break;
                }

                Log::info('Checking for prize:' . $randomPrize['id']);

                // check if the last prize given is the same as the random prize - then we need to find another prize
                if ($randomPrize['id'] != $lastPrizeDistributionId) {
                    if ($randomPrize['total_allocated_count'] < $randomPrize['max_allowed_total']) {
                        // check if we have given away max allowed per day for this prize
                        $allocated_this_day = PrizeDistribution::findTotalPrizeDistributedPerDay(
                            $randomPrize['id'],
                            $day
                        );
                        if ($allocated_this_day < $randomPrize['max_allowed_per_day']) {
                            // check if prize then we need to distribute it evenly spread over a period of 5 hours
                            // find the current count for this hour
                            $allocated_this_hour = PrizeDistribution::findTotalPrizeDistributedThisHourAndDay(
                                $randomPrize['id'],
                                $day
                            );

                            // find the allowed per hour value for this prize
                            if ($allocated_this_hour > $randomPrize['max_allowed_per_day'] / 6) {
                                $ignoreIds[] = $randomPrize['id'];
                                Log::info('Prize Allocated this hour Count is greater:' . $randomPrize['id'] . ':' . config('app.selected_day'));
                            } else
                                break;
                        } else {
                            $ignoreIds[] = $randomPrize['id'];
                            Log::info('Prize Allocated this day Count is greater:' . $randomPrize['id'] . ':' . config('app.selected_day'));
                        }
                    } else {
                        $ignoreIds[] = $randomPrize['id'];
                        Log::info('Prize Total Allocated Count is greater:' . $randomPrize['id']);
                    }
                } else {
                    $ignoreIds[] = $randomPrize['id'];
                    Log::info('Prize same as last distributed:' . $randomPrize['id']);
                }

                Log::info(json_encode($ignoreIds));
                $count++;
            }
        } catch (\Exception $ex) {
            dd($ignoreIds, $ex->getMessage());
        }

        if ($randomPrize)
            return Arr::only($randomPrize, ['id', 'name', 'title', 'description', 'degree', 'display_order']);

        // we need to return the default prize - so that user has at-least one prize
        return Prize::whereIn('id', [self::DEFAULT_PRIZE_IDENTIFIER])->first(['id', 'name', 'title', 'description', 'degree', 'display_order'])->toArray();
    }

    public static function anyPrizeAvailable()
    {
        // get whether any prize is available also or not
        return Prize::whereNot('id', 6)->count() !=
            Prize::whereNot('id', 6)->whereColumn('total_allocated_count', '>=', 'max_allowed_total')->count();
    }
}
