ldc-gen-game-web/app/Http/Controllers/Bo/InstantWinController.php
2026-10-20 12:27:49 +02:00

186 lines
6.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Models\InstantWin;
use App\Models\Prize;
use App\Models\Settings;
use Carbon\Carbon;
use Carbon\CarbonInterface;
use Carbon\CarbonInterval;
use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use stdClass;
class InstantWinController extends Controller
{
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(InstantWin::class);
}
/**
* Display a listing of the resource.
*/
public function index(): View
{
$instantWinModelList = InstantWin::query()->oldest('available_at')->get();
/** @var view-string $view */
$view = 'back::pages.instant-win.index';
return view($view, [
'instantWinModelList' => $instantWinModelList,
]);
}
/**
* Returns generated instant win.
*/
public function generate(): JsonResponse
{
$this->authorize('generate', InstantWin::class);
return DB::transaction(function () {
/**
* À partir de quelle heure on peut gagner
* ! Seul l'heure sera prize en compte
*/
$day_start = now()->setTime(6, 0);
/**
* Jusqu'à quelle heure on peut gagner
* ! Seul l'heure sera prize en compte
*/
$day_end = now()->setTime(22, 29);
/** @var Settings */
$settings = resolve(Settings::class);
$prizeModelList = Prize::all();
/** @var Collection<array-key, WinDayCalendar> */
$datesGlobal = collect();
/** @var Collection<array-key, WinTimeElement> Liste de tous les lots à gagner */
$lotsGlobal = collect();
// * Seed srand !
\mt_srand(time());
// * Init prize list
$prizeModelList->each(function (Prize $prize) use ($lotsGlobal, $day_start, $day_end): void {
for ($i = 0; $i < $prize->quantity; $i++) {
$el = new WinTimeElement();
$el->prize = $prize;
$el->time = now()->setTime(
mt_rand($day_start->hour, $day_end->hour),
mt_rand($day_start->minute, $day_end->minute)
);
$lotsGlobal->push($el);
}
});
$lotsGlobal->shuffle();
// * Init days calendar
foreach ($settings->start_date->toPeriod($settings->end_date, CarbonInterval::make('1day')) as $date) {
$el = new WinDayCalendar();
$el->lots = collect();
$el->time = $date->setTime(0, 0);
$datesGlobal->push($el);
}
// * Save Instant wins
$this->generateArray($lotsGlobal, $datesGlobal, 0)->each(function (WinDayCalendar $winDayCalendar): void {
$winDayCalendar->lots->each(function (WinTimeElement $winTimeElement): void {
$instantWin = new InstantWin();
$instantWin->available_at = $winTimeElement->time;
$instantWin->prize()->associate($winTimeElement->prize);
$instantWin->saveOrFail();
});
});
// * Output instant wins to ajax response
return response()->json(InstantWin::all());
});
}
/**
* Generate instant win.
*
* Même algo que celui implémenté par Romain.
*
* @param Collection<array-key, WinTimeElement> $lotsGlobal
* Liste de tous les lots à gagner
* @param Collection<array-key, WinDayCalendar> $dateGlobal
* @return Collection<array-key, WinDayCalendar>
*
* @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint
*/
private function generateArray(Collection $lotsGlobal, Collection $dateGlobal, int $prizesDone): Collection
{
// phpcs:enable
/** @var array-key Un jour sélectionné aléatoire. */
$rKey = $dateGlobal->keys()->random(1)->firstOrFail();
// ? À-t-on déjà assigné un lot par jour (au moins) ?
// ? Le jour aléatoire sélectionné à déja un lot ?
if ($prizesDone < $dateGlobal->count() && $dateGlobal->get($rKey)->lots->count() > 0) {
return $this->generateArray($lotsGlobal, $dateGlobal, $prizesDone);
}
// * Insert next prize on a randowm day
$dateGlobal->get($rKey)->lots->push($lotsGlobal->get($prizesDone++));
// ? On a distribué assez de lots ?
if ($prizesDone < $lotsGlobal->count()) {
return $this->generateArray($lotsGlobal, $dateGlobal, $prizesDone);
}
// * Tri par heure et assignation du jour correct.
$dateGlobal->each(function (WinDayCalendar $date): void {
$date->lots = $date->lots->sort(fn (WinTimeElement $a, WinTimeElement $b): int | float => $a->time->timestamp - $b->time->timestamp)
->map(function (WinTimeElement $time) use ($date): WinTimeElement {
$time->time->setDate(
$date->time->year,
$date->time->month,
$date->time->day
);
return $time;
});
});
return $dateGlobal;
}
}
/**
* @property Prize $prize Le lot à gagner.
* @property Carbon $time Une heure aléatoire.
*
* @phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses
*/
class WinTimeElement extends stdClass
{
// phpcs:enable
}
/**
* @property Carbon|CarbonInterface $time
* Un jour dans le temps.
* @property Collection<array-key, WinTimeElement> $lots
* Liste des lots tombant ce jour.
*
* @phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses
*/
class WinDayCalendar extends stdClass
{
// phpcs:enable
}