<?php

namespace App\Http\Controllers\Owner\BookingExtraPassenger;

use App\Http\Controllers\Controller;
use App\Http\Controllers\Owner\BookingExtraPassenger\Dto\BookingExtraPassengerSimpleUpdateDTO;
use App\Http\Controllers\Owner\Passenger\PassengerUpdater;
use Illuminate\Http\Request;
use App\Http\Helpers\ResponseBuilder;
use App\Http\Helpers\ParamsValidator;
use App\Http\History\HistoryData;
use App\Http\History\HistoryTables;
use App\Modules\BookingExtraPassenger\Application\Index\IndexBookingExtraPassengerQuery;
use App\Modules\BookingExtraPassenger\Application\Index\IndexBookingExtraPassengerResponse;
use App\Modules\Room\Application\Index\IndexRoomQuery;
use App\Modules\Room\Application\ReloadPassengerAmount\ReloadPassengerAmountRoomQuery;
use App\Modules\RoomPassenger\Application\List\ListRoomPassengerQuery;
use App\Modules\RoomPassenger\Application\RoomPassengerResponses;
use App\Modules\Shared\Application\ActionHandler;
use App\Modules\Shared\Domain\Bus\Event\EventBus;
use App\Modules\Shared\Domain\Bus\Query\QueryBus;
use App\Modules\Shared\Domain\GenerateActionException;
use Illuminate\Support\Facades\DB;

class BookingExtraPassengerSimpleUpdateController extends Controller
{
    private $oDomain;
    /** @var HistoryData */
    private $history;

    public function __construct(
        private EventBus $eventBus,
        private PassengerUpdater $passengerUpdater,
        private QueryBus $queryBus
    ) {
        $this->oDomain = "BookingExtraPassenger";
        $this->history = new HistoryData(HistoryTables::BOOKING_EXTRA_PASSENGER);
    }

    public static function findBooking($Id_BookingExtraPassenger)
    {
        $found = DB::select('SELECT `fn_booking_tour_detail_passenger_find_booking`(?,?) as Id_Booking', [$Id_BookingExtraPassenger, 2]);
        return count($found) ? $found[0]->Id_Booking : null;
    }

    public function __invoke(Request $request)
    {
        $oResponse  = array();
        $oValParams = BookingExtraPassengerSimpleUpdateDTO::validateData();

        // VALIDANDO DATOS
        $oResponse = ParamsValidator::Validate_Request($request, $oValParams, $this->oDomain);

        $Id_BookingExtraPassenger = $request->input("Id_BookingExtraPassenger");
        $BookingExtraPassenger_DateEntryStart = $request->input("BookingExtraPassenger_DateEntryStart");
        $BookingExtraPassenger_DateEntryEnd = $request->input("BookingExtraPassenger_DateEntryEnd");

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {

            $this->history->obtainOld($Id_BookingExtraPassenger);
            $oData_ExtraPax = DB::select('call sp_booking_extra_passenger_index(?)', [$Id_BookingExtraPassenger]);

            if ($this->isTicketBuyed($oData_ExtraPax)) {
                (new GenerateActionException())->__invoke('Ticket de pasajero no se puede modificar por estar comprado.');
            }

            $rooms = $this->attemptToUpdateRooms($oData_ExtraPax);

            /** @var IndexBookingExtraPassengerResponse */
            $response = $this->queryBus->ask(new IndexBookingExtraPassengerQuery($Id_BookingExtraPassenger));

            // $this->attemptToUpdate

            $oParam = [
                $BookingExtraPassenger_DateEntryStart,
                $BookingExtraPassenger_DateEntryEnd,
                $Id_BookingExtraPassenger
            ];
            $oData = DB::select('call sp_booking_extra_passenger_simple_update(?,?,?)', $oParam);

            if (count($oData_ExtraPax)) {
                (new ActionHandler())->handle(DB::select('CALL sp_invoice_reload(?, ?)', [$oData_ExtraPax[0]->Id_Passenger, 1]));
                (new ActionHandler())->handle(DB::select('CALL sp_passenger_check_info_pay(?)', [$oData_ExtraPax[0]->Id_Passenger]));
                $this->passengerUpdater->updateLockHtlCampBookingPassenger($oData_ExtraPax[0]->Id_Passenger);
            }

            if ($oData[0]->Response_Success == 1) {

                $this->reloadRoomsAmount($rooms);

                $this->history->update(
                    $this->findBooking($request->input("Id_BookingExtraPassenger")),
                    $this->history->oldValue,
                    [$request->all()],
                    $request
                );
            } else {
            }

            $oResponse["Response_Status"]           = $oData[0]->Response_Status;
            $oResponse["Response_Code"]             = $oData[0]->Response_Code;
            $oResponse["Response_Domain"]           = $this->oDomain;
            $oResponse["Response_Message"]          = $oData[0]->Response_Message;
            $oResponse["Response_Data"]             = null;
            $oResponse["Response_Error_Message"]    = $oData[0]->Response_Message;
            $oResponse["Response_Error_Reason"]     = $oData[0]->Response_Reason;
        }

        return ResponseBuilder::Response($oResponse);
    }

    private function isTicketBuyed($ticketData)
    {
        return count($ticketData) && $ticketData[0]->BookingExtraPassenger_Status === 2;
    }

    private function attemptToUpdateRooms($beps)
    {
        if (!count($beps)) {
            return;
        }
        $responses = $this->listRoomPassengers($beps[0]->Id_BookingExtraPassenger);
        $rooms = $this->findRoomsWithoutRepeat($responses->data());
        if ($this->someRoomLock($rooms)) {
            (new GenerateActionException())->__invoke('Habitación de pasajero no se puede actualizar por estar comprado');
        }
        return $rooms;
    }

    private function listRoomPassengers($idBookingExtraPassenger): RoomPassengerResponses
    {
        return $this->queryBus->ask(new ListRoomPassengerQuery('all', $idBookingExtraPassenger, null));
    }

    private function findRoomsWithoutRepeat($roomPassengers)
    {
        $rooms = [];
        foreach ($roomPassengers as $roomPassenger) {
            if (!isset($rooms[$roomPassenger->Id_Room])) {
                /** @var RoomResponse */
                $rooms[$roomPassenger->Id_Room] = $this->queryBus->ask(new IndexRoomQuery($roomPassenger->Id_Room, ''));
            }
        }
        return $rooms;
    }

    private function someRoomLock($rooms)
    {
        foreach ($rooms as $room) {
            if ($room->Room_Lock == 2) {
                return true;
            }
        }
    }

    private function reloadRoomsAmount($rooms)
    {
        foreach ($rooms as $room) {
            $this->queryBus->ask(new ReloadPassengerAmountRoomQuery($room->Id_Room));
        }
    }
}
