<?php

namespace App\Modules\Room\Application\ReloadPassengerAmount;

use App\Modules\BookingExtraPassenger\Domain\IdBookingExtraPassenger;
use App\Modules\Passenger\Domain\IdPassenger;
use App\Modules\PaxInformationRoomPassenger\Domain\IdPaxInformationRoomPassenger;
use App\Modules\Room\Domain\ExistsRoom;
use App\Modules\Room\Domain\IdRoom;
use App\Modules\Room\Domain\Room;
use App\Modules\Room\Domain\RoomNoValidAmount;
use App\Modules\Room\Domain\RoomPassengersAmount;
use App\Modules\Room\Domain\RoomRepository;
use App\Modules\RoomPassenger\Domain\IdRoomPassenger;
use App\Modules\RoomPassenger\Domain\RoomPassenger;
use App\Modules\RoomPassenger\Domain\RoomPassengerIsNotValid;
use App\Modules\RoomPassenger\Domain\RoomPassengerRepository;
use App\Modules\RoomPassenger\Domain\RoomPassengerStatus;
use App\Modules\Shared\Domain\DateUtils;
use App\Modules\Shared\Domain\Transaction;

final class RoomPassengerAmountReloader
{
    public function __construct(
        private RoomRepository $repository,
        private RoomPassengerRepository $roomPassengerRepository,
        private Transaction $transaction
    ) {}

    public function __invoke(
        IdRoom $idRoom,
        bool $avoidTransaction = false,
        bool $lockInShare = false
    ) {
        $this->transaction->transactional(
            fn() => $this->run($idRoom, $lockInShare),
            $avoidTransaction
        );
    }

    private function run(IdRoom $idRoom, bool $lockInShare)
    {
        /** @var Room $index */
        $index = $this->repository->find(new ExistsRoom($idRoom, $lockInShare));
        $roomPassenger = $this->roomPassengerRepository->list($idRoom->value());
        $index->setPassengerAmount(new RoomPassengersAmount(count($roomPassenger)));
        if ($index->idBookingExtra()->value() == 0) {
            $this->repository->update($index);
            return;
        }
        foreach ($roomPassenger as $rp) {
            $days = DateUtils::dateDiferenceInDays($rp->BookingExtraPassenger_DateEntryStart, $index->requestDateStart()->value(), 'Y-m-d H:i:s');

            if ($days != 0) {
                $rp->RoomPassenger_IsNotValid = 2;
            } else {
                $rp->RoomPassenger_IsNotValid = 1;
            }
            $this->updateRoomPassenger($rp);
        }

        $index->setNoValidAmount(new RoomNoValidAmount(
            count(array_values(array_filter($roomPassenger, fn($rp) => $rp->RoomPassenger_IsNotValid == 2)))
        ));
        $this->repository->update($index);
    }

    private function updateRoomPassenger($rp)
    {
        $this->roomPassengerRepository->update(
            new RoomPassenger(
                new IdRoomPassenger($rp->Id_RoomPassenger),
                new RoomPassengerIsNotValid($rp->RoomPassenger_IsNotValid),
                new RoomPassengerStatus($rp->RoomPassenger_Status),
                new IdBookingExtraPassenger($rp->Id_BookingExtraPassenger),
                new IdRoom($rp->Id_Room),
                new IdPassenger($rp->Id_Passenger),
                new IdPaxInformationRoomPassenger($rp->Id_PaxInformationRoomPassenger),
            )
        );
    }
}
