<?php

namespace App\Modules\HtlCampBooking\Application\CreateWithPassengers;

use App\Modules\BookingTour\Domain\IdBookingTour;
use App\Modules\BookingTourPassenger\Application\Index\IndexBookingTourPassengerQuery;
use App\Modules\BookingTourPassenger\Application\Index\IndexBookingTourPassengerResponse;
use App\Modules\BookingTourPassenger\Domain\BookingTourPassenger;
use App\Modules\HtlCampBooking\Application\Create\HtlCampBookingCreator;
use App\Modules\HtlCampBooking\Application\ReloadAmount\ReloadAmountHtlCampBookingQuery;
use App\Modules\HtlCampBooking\Domain\HtlCampBooking;
use App\Modules\HtlCampBooking\Domain\HtlCampBookingAmount;
use App\Modules\HtlCampBooking\Domain\HtlCampBookingDateStart;
use App\Modules\HtlCampBookingPassenger\Application\Create\CreateHtlCampBookingPassengerQuery;
use App\Modules\HtlCampBookingPassenger\Domain\HtlCampBookingPassengerStatus;
use App\Modules\HtlCampBookingPassenger\Domain\HtlCampBookingPassengerWeight;
use App\Modules\HtlCampSchedule\Application\Availability\AvailabilityHtlCampScheduleQuery;
use App\Modules\HtlCampSchedule\Application\HtlCampScheduleResponse;
use App\Modules\HtlCampSchedule\Domain\IdHtlCampSchedule;
use App\Modules\Shared\Domain\Bus\Query\QueryBus;
use App\Modules\Shared\Domain\Bus\Query\QueryHandler;
use Illuminate\Support\Facades\DB;

final class CreateWithPassengersHtlCampBookingQueryHandler implements QueryHandler
{
    public function __construct(
        private HtlCampBookingCreator $htlCampBookingCreator,
        private QueryBus $queryBus
    ) {
    }

    public function __invoke(CreateWithPassengersHtlCampBookingQuery $query): CreateWithPassengersHtlCampBookingResponse
    {
        $passengers = $this->findBookingTourPassengers($query->passengers());
        $bookingTour = $this->findBookingTour($query->idBookingTour());
        $availability = $this->getAvailability($query->idHtlCamp(), $query->dateStart(), 0);
        [$camp, $idHtlCampBooking] = $this->createCampBooking($query->dateStart(), $availability->Id_HtlCampSchedule, $bookingTour->Id_BookingTour);
        $this->createPassengers($idHtlCampBooking, $passengers);
        $this->queryBus->ask(new ReloadAmountHtlCampBookingQuery($idHtlCampBooking));
        return new CreateWithPassengersHtlCampBookingResponse($idHtlCampBooking);
    }

    /** @param CreateWithPassengersHtlCampBookingPassenger[] $passengers */
    private function findBookingTourPassengers(array $passengers)
    {
        return array_map(
            [$this, 'findBookingTourPassenger'],
            $passengers
        );
    }

    private function findBookingTour($bookingTour)
    {
        $index = DB::select('call sp_booking_tour_index(?)', [$bookingTour]);
        return $index[0];
    }

    private function findBookingTourPassenger($passenger)
    {
        $query = new IndexBookingTourPassengerQuery($passenger->idBookingTourPassenger());
        /** @var IndexBookingTourPassengerResponse */
        $response = $this->queryBus->ask($query);
        return $response->response()[0];
    }


    private function getAvailability($idHtlCamp, $dateStart, $amount): HtlCampScheduleResponse
    {
        return $this->queryBus->ask(new AvailabilityHtlCampScheduleQuery($idHtlCamp, $dateStart, $amount));
    }

    private function createCampBooking($dateStart, $idHtlCampSchedule, $idBookingTour)
    {
        $campBooking = HtlCampBooking::generatePassenger(
            new HtlCampBookingDateStart($dateStart),
            new HtlCampBookingAmount(0),
            new IdHtlCampSchedule($idHtlCampSchedule),
            new IdBookingTour($idBookingTour),
        );
        $response = $this->htlCampBookingCreator->__invoke($campBooking);
        return [$campBooking, $response];
    }

    /**
     * @param $passengers
     */
    private function createPassengers($idHtlCampBooking, $passengers)
    {
        foreach ($passengers as $passenger) {
            $this->queryBus->ask(new CreateHtlCampBookingPassengerQuery(
                HtlCampBookingPassengerWeight::defaultValue(),
                HtlCampBookingPassengerStatus::ACTIVE,
                $idHtlCampBooking,
                $passenger->Id_BookingTourPassenger
            ));
        }
    }
}
