<?php

namespace App\Http\Controllers\Client;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Http\Helpers\ResponseBuilder;
use App\Http\Helpers\ParamsValidator;
use App\Mail\c_Mail_User;
use Illuminate\Support\Facades\Mail;
use App\Http\Controllers\Owner\Booking as Owner_Booking;
use App\Http\Controllers\Owner\BookingCreator;
use App\Http\Controllers\Owner\Passenger\PassengerUpdater;
use App\Modules\Booking\Infraestructure\BookingValidators;
use App\Modules\PackageFee\Application\GetFull\PackageFeeGetFullQuery;
use App\Modules\PackageFee\Application\GetFull\PackageFeeGetFullQueryResponse;
use App\Modules\Shared\Domain\Bus\Query\QueryBus;
use App\Modules\Shared\Domain\ValueObject\DateValueObject;
use App\Modules\Shared\Infraestructure\LaravelExceptionHandler;
use App\Modules\Shared\Validator\Infraestructure\LaravelValidator;
use App\Providers\BookingMailSender;
use Exception;
use Illuminate\Support\Facades\DB;
use \Throwable;

class c_Booking extends Controller
{
    private $oDomain;

    public function __construct(
        private QueryBus $queryBus,
        private BookingCreator $bookingCreator,
        private PassengerUpdater $passengerUpdater
    ) {
        $this->oDomain = "Booking";
    }

    public function Insert(Request $request)
    {
        try {
            return $this->InsertBooking($request);
        } catch (Throwable $ex) {
            return (new LaravelExceptionHandler())->handle($ex);
        }
    }

    public function InsertBooking(Request $Request)
    {
        $Id_User            = 0;
        $Id_Booking         = 0;
        $Id_BookingTour     = 0;
        $Id_BookingUpgrade  = 0;
        $Id_BookingExtra    = 0;
        $Token              = "";
        $oData              = null;

        $oResponse  = array();

        (new LaravelValidator())->validate($Request->all(), $this->oDomain, BookingValidators::INSERT);

        //region USER

        $userId = $Request->input('Id_User');
        $Token  = $Request->header('Token');
        if ($Request->input('Id_User') == 0) {
            $oClient = DB::select('CALL sp_client_user_validate(?)', [$Request->input('User_Email')]);
            if ($oClient[0]->Response_Id != null) {
                $userId = $oClient[0]->Response_Id;
                $Token = DB::select('CALL sp_client_user_session_insert_empty(?)', [$userId])[0]->Response_Token;
            }
        }

        if ($userId == 0) {
            $oParam     = [
                $Request->input("User_Name"),
                $Request->input("User_LastName"),
                $Request->input("User_Email"),
                $Request->input("User_Phone"),
                $Request->input("Id_UserCountry")
            ];

            $oData_User = DB::select('call sp_client_user_insert(?,?,?,?,?)', $oParam);
            $Id_User = $oData_User[0]->Response_Id;

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

                $Variables  = [
                    "Lang"          => 1,
                    "User"          => $Request->input("User_Email"),
                    "Password"      => $oData_User[0]->Response_Password,
                    'ResourcesUrl'  => BookingMailSender::getResourcesUrl()[0]->Credential_Value,
                    'WebUrl'        => BookingMailSender::getClientWebUrl()[0]->Credential_Value
                ];

                $oMail_User             = new c_Mail_User;
                $oMail_User->Type       = 1;
                $oMail_User->Subject    = "Your Account Password";
                $oMail_User->Content    = $Variables;

                try {
                    if (config('var.SEND_AUTO_ACCESSDATA')) {
                        Mail::to($Request->input("User_Email"))->send($oMail_User);
                    } else {
                        Mail::to(config('var.SEND_EMAIL_ACCESSDATA'))->send($oMail_User);
                    }
                } catch (Throwable $ex) {
                }
            }

            //region INICIA SESION DE USUARIO
            $oParam = array(
                $oData_User[0]->Response_User_Email,
                $oData_User[0]->Response_Password
            );

            $oData_User_Session = DB::select('call sp_client_user_session_insert(?,SHA1(?))', $oParam);
            $Token              = $oData_User_Session[0]->Response_Token;
            //endregion
        } else {
            $Id_User    = $userId;
        }
        //endregion

        //
        //  DESERIALIZA DATOS DE LA RESERVA
        //
        $oBooking       = json_decode($Request->input("Booking"));

        $oCashMovement  = json_decode($Request->input("CashMovement"));

        $oParam = [
            DateValueObject::reducedNowToPeru(),
            $oCashMovement->CashMovement_Amount,
            $oCashMovement->CashMovement_Currency,
            $oCashMovement->CashMovement_Name,
            $oCashMovement->CashMovement_LastName,
            $oCashMovement->CashMovement_Email,
            $oCashMovement->CashMovement_Country,
            $oCashMovement->CashMovement_City,
            $oCashMovement->CashMovement_Address,
            $oCashMovement->CashMovement_Phone,
            $oCashMovement->CashMovement_ReceiptNumber,
            $oCashMovement->CashMovement_CardLast,
            $oCashMovement->CashMovement_CardNumber,
            $oCashMovement->CashMovement_CardBrand,
            $oCashMovement->CashMovement_CardType,
            $oCashMovement->CashMovement_CardIssuer,
            '',
            14
        ];

        $oDataCashMovement = DB::select('call sp_cash_movement_insert(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,0)', $oParam);

        if ($oDataCashMovement[0]->Response_Success) {

            if (count($oBooking) > 0) {
                $oData = $oData_Booking = $this->insertGenericBooking($oBooking[0], $Id_User);

                if ($oData_Booking[0]->Response_Success == 1) {
                    $Id_Booking = $oData_Booking[0]->Response_Id;

                    /** @var $oBookingHighPassenger */
                    $oBookingHighPassenger = $this->getBookingHighPassenger($oBooking);

                    $this->insertPassengerList($oBookingHighPassenger->Passenger, $Id_Booking);

                    $oPassenger = $this->listPassengers($Id_Booking);

                    foreach ($oBooking as $k => $oBookingElement) {

                        // $oPassenger      = $oBooking[$k]->Passenger;
                        $oTour          = $oBooking[$k]->Tour;
                        foreach ($oTour as $j => $oTourElement) {
                            if (!$this->isFirstTour($j)) {
                                $tour = $this->getTour($oTour[$j - 1]->Id_Tour);
                                $oTour[$j]->BookingTour_DateStart = $this->setDateFromLastTour($tour[0], $oTour[$j - 1]);
                            }
                            try {
                                /** @var PackageFeeGetFullQueryResponse $response */
                                $response = $this->queryBus->ask(new PackageFeeGetFullQuery($oBooking[$k]->Id_Package));
                                $oParam         = array(
                                    $oTour[$j]->BookingTour_DateStart,
                                    $oBooking[$k]->Booking_Type,
                                    $oBooking[$k]->Booking_NoPax,
                                    $response->packageFeeType(),
                                    $response->packageFeeTotal(),
                                    $oBooking[$k]->Id_Package,
                                    $Id_Booking,
                                    $oTour[$j]->Id_Tour,
                                    $k + 1
                                );
                                $oData_Tour     = DB::select('call sp_booking_tour_insert_unregistered(?,?,?,?,?,?,?,?,?)', $oParam);

                                $Id_BookingTour = $oData_Tour[0]->Response_Id;
                                $camps = $this->bookingCreator->addHtlCampBookings(
                                    $Id_BookingTour,
                                    $oTour[$j]->BookingTour_DateStart,
                                    $oTour[$j]->Id_Tour
                                );
                                $oUpgrade       = $oTour[$j]->Upgrade;
                                $oExtra         = $oTour[$j]->Extra;

                                for ($h = 0; $h < count($oPassenger) && $h < $oBookingElement->Booking_NoPax; $h++) {
                                    $oParam = array(
                                        $Id_BookingTour,
                                        $oPassenger[$h]->Id_Passenger,
                                        count($oPassenger)
                                    );

                                    $oResponseTourPassenger = DB::select('call sp_booking_tour_passenger_insert(?,?,?)', $oParam);
                                    $idBookingTourPassenger = $oResponseTourPassenger[0]->Response_Id;

                                    array_map(fn ($camp) => $this->bookingCreator->addHtlCampBookingPassenger(
                                        $camp->id(),
                                        $idBookingTourPassenger
                                    ), $camps);
                                }

                                $oParam = array(
                                    "all",
                                    $Id_BookingTour,
                                    0,
                                    ''
                                );

                                $oTourPassenger = DB::select('call sp_booking_tour_passenger_list(?,?,?,?)', $oParam);

                                for ($i = 0; $i < count($oUpgrade); $i++) {
                                    //region BOOKING UPGRADE
                                    $oParam             = array(
                                        $oBooking[$k]->Booking_NoPax,
                                        "",
                                        1,
                                        $Id_BookingTour,
                                        0,
                                        $oUpgrade[$i]->Id_Upgrade,
                                        1,
                                        1
                                    );

                                    $oData_Upgrade      = DB::select('call sp_booking_upgrade_insert(?,?,?,?,?,?,?,?)', $oParam);
                                    $Id_BookingUpgrade  = $oData_Upgrade[0]->Response_Id;
                                    //endregion

                                    //region BOOKING UPGRADE PASSENGER
                                    for ($h = 0; $h < count($oTourPassenger); $h++) {
                                        $oParam                     = array(
                                            $Id_BookingUpgrade,
                                            $oTourPassenger[$h]->Id_BookingTourPassenger,
                                            1
                                        );
                                        $oData_UpgradePassenger = DB::select('call sp_booking_upgrade_passenger_insert(?,?,?)', $oParam);
                                    }
                                    //endregion
                                }

                                for ($i = 0; $i < count($oExtra); $i++) {
                                    //region BOOKING EXTRA
                                    $oParam             = array(
                                        $oBooking[$k]->Booking_NoPax,
                                        " ",
                                        1,
                                        $Id_BookingTour,
                                        0,
                                        $oExtra[$i]->Id_Extra,
                                        1,
                                        1
                                    );

                                    $oData_Extra        = DB::select('call sp_booking_extra_insert(?,?,?,?,?,?,?,?)', $oParam);
                                    $Id_BookingExtra    = $oData_Extra[0]->Response_Id;

                                    //endregion

                                    //region BOOKING EXTRA PASSENGER
                                    for ($h = 0; $h < count($oTourPassenger); $h++) {
                                        $oParam                 = array(
                                            $Id_BookingExtra,
                                            $oTourPassenger[$h]->Id_BookingTourPassenger,
                                            1
                                        );
                                        $oData_ExtraPassenger   = DB::select('call sp_booking_extra_passenger_insert(?,?,?)', $oParam);
                                    }
                                    //endregion
                                }
                                DB::select('CALL sp_booking_tour_add_items_from_package_tour(?,?)', [$Id_BookingTour, 1]);
                            } catch (Throwable $th) {
                            }
                        }
                    }

                    $passengerLength = count($oPassenger);
                    //region INVOICE
                    for ($i = 0; $i < $passengerLength; $i++) {
                        $oParam = [
                            $Id_Booking,
                            $oPassenger[$i]->Id_Passenger,
                            1
                        ];

                        $oData_Invoice  = DB::select('call sp_invoice_insert(?,?,?)', $oParam);

                        $oData          = $oData_Invoice;
                        $sum = 0;
                        foreach ($oBooking as $j => $booking) {
                            if ($i >= $booking->Booking_NoPax) {
                                continue;
                            }
                            $sum += $booking->CashMovementDetail_Amount / $booking->Booking_NoPax;
                        }

                        DB::select('call sp_cash_movement_detail_insert(?,?,?,?,?)', [
                            $sum,
                            $oDataCashMovement[0]->Id_CashMovement,
                            $oData_Invoice[0]->Response_Id,
                            1,
                            1
                        ]);
                        $this->passengerUpdater->updateLockHtlCampBookingPassenger($oPassenger[$i]->Id_Passenger);
                    }
                    //endregion
                    try {
                        BookingMailSender::sendBookingByMail($Id_Booking, $this->oDomain, BookingMailSender::REGULAR_AND_PAYMENT);
                    } catch (\Throwable $ex) {
                    }
                }
            }
        } else {
            $oData = $oDataCashMovement;
        }



        $Response_Data  = array(
            "Id_Booking"    => $Id_Booking,
            "Id_User"       => $Id_User,
            "Token"         => $Token
        );


        $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"]             = $Response_Data;
        $oResponse["Response_Error_Message"]    = $oData[0]->Response_Message;
        $oResponse["Response_Error_Reason"]     = $oData[0]->Response_Reason;


        return ResponseBuilder::Response($oResponse);
    }

    public function getTour($idTour)
    {
        return DB::select('CALL sp_tour_index(?)', [$idTour]);
    }

    public function isFirstTour($index)
    {
        return $index == 0;
    }

    public function setDateFromLastTour($lastTour, $lastBookingTour)
    {
        /** date from lastBookingTour + duration */
        return date('Y-m-d', strtotime($lastBookingTour->BookingTour_DateStart) + $lastTour->Tour_Duration * 24 * 3600);
    }

    public function insertGenericBooking($booking, $Id_User)
    {
        $oParam = [
            $booking->Booking_DateStart,
            1,
            1,
            '',
            '',
            $booking->Id_Language,
            $booking->Id_Language,
            $Id_User,
            0,
            1,
            1,
            1,
            ""
        ];
        return DB::select('call sp_booking_insert(?,?,?,?,?,?,?,?,?,?,?,?,?)', $oParam);
    }

    public function getBookingHighPassenger(array $bookingList)
    {
        return array_reduce($bookingList, function ($carry, $booking) {
            if ($carry == null) {
                return $booking;
            }
            return $carry->Booking_NoPax < $booking->Booking_NoPax ? $booking : $carry;
        }, null);
    }

    public function insertPassengerList($passengerList, $Id_Booking)
    {
        foreach ($passengerList as $passenger) {
            $Id_TypeDocument = $passenger->Id_TypeDocument ? $passenger->Id_TypeDocument : 1;
            $Id_UserCountry = $passenger->Id_UserCountry ? $passenger->Id_UserCountry : 1;
            $oParam = [
                Str::title($passenger->Passenger_Name),
                Str::title($passenger->Passenger_LastName),
                $passenger->Passenger_Email,
                '',
                $passenger->Passenger_Phone,
                $passenger->Passenger_Gender,
                $passenger->Passenger_DOB,
                Str::upper(trim($passenger->Passenger_NoDocument)),
                date('Y-m-d H:i:s'),
                $passenger->Passenger_Restriction,
                $passenger->Passenger_Extras,
                2,
                2,
                $Id_Booking,
                $Id_TypeDocument,
                $passenger->Id_TypeRate,
                $Id_UserCountry
            ];
            DB::select('call sp_passenger_insert(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', $oParam);
        }
    }

    public function listPassengers($Id_Booking)
    {
        $Path_ImgDocument1_Thumb    = config("var.PATH_PUBLIC") . config("var.PASSENGER_IMGDOCUMENT1_THUMB");
        $Path_ImgDocument1_Large    = config("var.PATH_PUBLIC") . config("var.PASSENGER_IMGDOCUMENT1_LARGE");
        $Path_ImgDocument2_Thumb    = config("var.PATH_PUBLIC") . config("var.PASSENGER_IMGDOCUMENT2_THUMB");
        $Path_ImgDocument2_Large    = config("var.PATH_PUBLIC") . config("var.PASSENGER_IMGDOCUMENT2_LARGE");

        $oParam = [
            'all',
            $Id_Booking,
            0,
            $Path_ImgDocument1_Thumb,
            $Path_ImgDocument1_Large,
            $Path_ImgDocument2_Thumb,
            $Path_ImgDocument2_Large
        ];

        return DB::select('call sp_passenger_list(?,?,?,?,?,?,?)', $oParam);
    }

    public function testSuccess($oResponse)
    {
        if ($oResponse[0]->Response_Code != 200) {
            throw new Exception(json_encode($oResponse));
        }
    }

    public function InsertEndorser(Request $Request)
    {
        $Id_User            = 0;
        $Id_Booking         = 0;
        $Id_BookingTour     = 0;
        $Id_BookingUpgrade  = 0;
        $Id_BookingExtra    = 0;
        $Token              = $Request->header('Token');
        $oData              = null;


        $oResponse  = array();
        $oValParams = array(
            'Id_User'       => 'int',
            'Booking'       => 'required|string',
            'CashMovement'          => 'required|string'
        );

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

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

            //region USER
            $Id_User = $Request->input("Id_User");
            //endregion

            //
            //  DESERIALIZA DATOS DE LA RESERVA
            //
            $oBooking   = json_decode($Request->input("Booking"));
            $oCashMovement  = json_decode($Request->input("CashMovement"));

            $oDataCashMovement = null;
            if ($oCashMovement != null) {
                $oParam = [
                    DateValueObject::reducedNowToPeru(),
                    $oCashMovement->CashMovement_Amount,
                    $oCashMovement->CashMovement_Currency,
                    $oCashMovement->CashMovement_Name,
                    $oCashMovement->CashMovement_LastName,
                    $oCashMovement->CashMovement_Email,
                    $oCashMovement->CashMovement_Country,
                    $oCashMovement->CashMovement_City,
                    $oCashMovement->CashMovement_Address,
                    $oCashMovement->CashMovement_Phone,
                    $oCashMovement->CashMovement_ReceiptNumber,
                    $oCashMovement->CashMovement_CardLast,
                    $oCashMovement->CashMovement_CardNumber,
                    $oCashMovement->CashMovement_CardBrand,
                    $oCashMovement->CashMovement_CardType,
                    $oCashMovement->CashMovement_CardIssuer,
                    '',
                    1
                ];
                $oDataCashMovement = DB::select('call sp_cash_movement_insert(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,0)', $oParam);
            }


            if ($oDataCashMovement == null || $oDataCashMovement[0]->Response_Success) {


                for ($k = 0; $k < count($oBooking); $k++) {

                    //region BOOKING

                    $oParam         = array(
                        $oBooking[$k]->Booking_DateStart,
                        $oBooking[$k]->Booking_Receipt,
                        1,
                        $oBooking[$k]->Booking_Observation,
                        '',
                        $oBooking[$k]->Id_Language,
                        $oBooking[$k]->Id_GuideLanguage,
                        $Id_User,
                        0,
                        1,
                        1,
                        1,
                        ''
                    );
                    $oData_Booking  = DB::select('call sp_booking_insert(?,?,?,?,?,?,?,?,?,?,?,?,?)', $oParam);

                    //endregion

                    $oPassenger     = $oBooking[$k]->Passenger;
                    $oTour          = $oBooking[$k]->Tour;

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

                        $Id_Booking = $oData_Booking[0]->Response_Id;

                        //region INSERTA PASSENGER

                        for ($j = 0; $j < count($oPassenger); $j++) {
                            $Id_TypeDocument = $oPassenger[$j]->Id_TypeDocument ? $oPassenger[$j]->Id_TypeDocument : 1;
                            $Id_UserCountry = $oPassenger[$j]->Id_UserCountry ? $oPassenger[$j]->Id_UserCountry : 1;
                            $oParam = array(
                                Str::title($oPassenger[$j]->Passenger_Name),
                                Str::title($oPassenger[$j]->Passenger_LastName),
                                $oPassenger[$j]->Passenger_Email,
                                '',
                                $oPassenger[$j]->Passenger_Phone,
                                $oPassenger[$j]->Passenger_Gender,
                                $oPassenger[$j]->Passenger_DOB,
                                Str::upper(trim($oPassenger[$j]->Passenger_NoDocument)),
                                date('Y-m-d H:i:s'),
                                $oPassenger[$j]->Passenger_Restriction,
                                $oPassenger[$j]->Passenger_Extras,
                                2,
                                2,
                                $Id_Booking,
                                $Id_TypeDocument,
                                $oPassenger[$j]->Id_TypeRate,
                                $Id_UserCountry
                            );

                            $oData_Passenger = DB::select('call sp_passenger_insert(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', $oParam);

                            if ($oData_Passenger[0]->Response_Success == 0) {
                                $oData = $oData_Passenger;
                                break;
                            }
                        }

                        //endregion

                        //region LISTA LOS PASAJEROS DE UNA RESERVA

                        $Path_ImgDocument1_Thumb    = config("var.PATH_PUBLIC") . config("var.PASSENGER_IMGDOCUMENT1_THUMB");
                        $Path_ImgDocument1_Large    = config("var.PATH_PUBLIC") . config("var.PASSENGER_IMGDOCUMENT1_LARGE");
                        $Path_ImgDocument2_Thumb    = config("var.PATH_PUBLIC") . config("var.PASSENGER_IMGDOCUMENT2_THUMB");
                        $Path_ImgDocument2_Large    = config("var.PATH_PUBLIC") . config("var.PASSENGER_IMGDOCUMENT2_LARGE");

                        $oParam = array(
                            "all",
                            $Id_Booking,
                            0,
                            $Path_ImgDocument1_Thumb,
                            $Path_ImgDocument1_Large,
                            $Path_ImgDocument2_Thumb,
                            $Path_ImgDocument2_Large
                        );

                        $oPassenger = DB::select('call sp_passenger_list(?,?,?,?,?,?,?)', $oParam);

                        //endregion

                        //region INSERTA TOUR / UPGRADES / EXTRAS / EQUIPMENT 

                        for ($j = 0; $j < count($oTour); $j++) {

                            try {
                                /** @var PackageFeeGetFullQueryResponse $response */
                                $response = $this->queryBus->ask(new PackageFeeGetFullQuery($oBooking[$k]->Id_Package));

                                //region TOUR

                                $oParam         = array(
                                    $oTour[$j]->BookingTour_DateStart,
                                    $oBooking[$k]->Booking_Type,
                                    $oBooking[$k]->Booking_NoPax,
                                    $response->packageFeeType(),
                                    $response->packageFeeTotal(),
                                    $oBooking[$k]->Id_Package,
                                    $Id_Booking,
                                    $oTour[$j]->Id_Tour,
                                    1
                                );
                                $oData_Tour     = DB::select('call sp_booking_tour_insert_unregistered(?,?,?,?,?,?,?,?,?)', $oParam);

                                //endregion

                                $Id_BookingTour = $oData_Tour[0]->Response_Id;
                                $camps = $this->bookingCreator->addHtlCampBookings($Id_BookingTour, $oTour[$j]->BookingTour_DateStart, $oTour[$j]->Id_Tour);
                                $oUpgrade       = $oTour[$j]->Upgrade;
                                $oExtra         = $oTour[$j]->Extra;
                                $oEquipment     = $oTour[$j]->Equipment;

                                //region INSERTA BOOKING TOUR PASSENGER

                                for ($h = 0; $h < count($oPassenger); $h++) {

                                    $oParam                 = array(
                                        $Id_BookingTour,
                                        $oPassenger[$h]->Id_Passenger,
                                        count($oPassenger)
                                    );

                                    $insertResponse = DB::select('call sp_booking_tour_passenger_insert(?,?,?)', $oParam);
                                    $idBookingTourPassenger = $insertResponse[0]->Response_Id;
                                    $this->bookingCreator->addPassengerToAllHtlCamps($camps, $idBookingTourPassenger);
                                }

                                //endregion

                                //region RECUPERA LOS PASAJEROS DEL TOUR

                                $oParam = array(
                                    "all",
                                    $Id_BookingTour,
                                    0,
                                    ''
                                );

                                $oTourPassenger = DB::select('call sp_booking_tour_passenger_list(?,?,?,?)', $oParam);

                                //endregion


                                $Id_BookingTour = $oData_Tour[0]->Response_Id;
                                $oUpgrade       = $oTour[$j]->Upgrade;
                                $oExtra         = $oTour[$j]->Extra;
                                $oEquipment     = $oTour[$j]->Equipment;

                                //region BOOKING UPGRADE

                                for ($i = 0; $i < count($oUpgrade); $i++) {

                                    //region BOOKING UPGRADE

                                    $oParam             = array(
                                        $oBooking[$k]->Booking_NoPax,
                                        "",
                                        1,
                                        $Id_BookingTour,
                                        0,
                                        $oUpgrade[$i]->Id_Upgrade,
                                        1,
                                        1
                                    );

                                    $oData_Upgrade      = DB::select('call sp_booking_upgrade_insert(?,?,?,?,?,?,?,?)', $oParam);
                                    $Id_BookingUpgrade  = $oData_Upgrade[0]->Response_Id;

                                    //endregion

                                    //region BOOKING UPGRADE PASSENGER

                                    for ($h = 0; $h < count($oTourPassenger); $h++) {

                                        $oParam                     = array(
                                            $Id_BookingUpgrade,
                                            $oTourPassenger[$h]->Id_BookingTourPassenger,
                                            1
                                        );
                                        $oData_UpgradePassenger     = DB::select('call sp_booking_upgrade_passenger_insert(?,?,?)', $oParam);
                                    }

                                    //endregion
                                }

                                //endregion

                                //region BOOKING EXTRA

                                for ($i = 0; $i < count($oExtra); $i++) {

                                    //region BOOKING EXTRA

                                    $oParam             = array(
                                        $oBooking[$k]->Booking_NoPax,
                                        " ",
                                        1,
                                        $Id_BookingTour,
                                        0,
                                        $oExtra[$i]->Id_Extra,
                                        1,
                                        1
                                    );

                                    $oData_Extra        = DB::select('call sp_booking_extra_insert(?,?,?,?,?,?,?,?)', $oParam);
                                    $Id_BookingExtra    = $oData_Extra[0]->Response_Id;

                                    //endregion

                                    //region BOOKING EXTRA PASSENGER

                                    for ($h = 0; $h < count($oTourPassenger); $h++) {

                                        $oParam                 = array(
                                            $Id_BookingExtra,
                                            $oTourPassenger[$h]->Id_BookingTourPassenger,
                                            1
                                        );

                                        $oData_ExtraPassenger   = DB::select('call sp_booking_extra_passenger_insert(?,?,?)', $oParam);
                                    }

                                    //endregion

                                }

                                //endregion

                                //region BOOKING EQUIPMENT

                                for ($i = 0; $i < count($oEquipment); $i++) {

                                    //region BOOKING EQUIPMENT

                                    $oParam     =   [
                                        $oBooking[$k]->Booking_NoPax,
                                        1,
                                        $Id_BookingTour,
                                        $oEquipment[$i]->Id_Equipment,
                                        1,
                                        1
                                    ];

                                    $oData_Equipment        = DB::select('call sp_booking_equipment_insert(?,?,?,?,?,?)', $oParam);
                                    $Id_BookingEquipment    = $oData_Equipment[0]->Response_Id;

                                    //endregion

                                    //region BOOKING EXTRA PASSENGER

                                    for ($h = 0; $h < count($oTourPassenger); $h++) {

                                        $oParam                 = array(
                                            $Id_BookingEquipment,
                                            $oTourPassenger[$h]->Id_BookingTourPassenger,
                                            1,
                                            ""
                                        );

                                        $oData_EquipmentPassenger   = DB::select('call sp_booking_equipment_passenger_insert(?,?,?,?)', $oParam);
                                    }

                                    //endregion

                                }

                                DB::select('CALL sp_booking_tour_add_items_from_package_tour(?,?)', [$Id_BookingTour, 1]);

                                //endregion

                                // //region RECUPERA PREGUNTAS DE TOUR

                                // $oParam          = array( $oTour[$j]->Id_Tour );
                                // $oQuestion       = DB::select('call sp_tour_question_list(?)',$oParam);

                                // //endregion

                                // //region INSERTA PREGUNTAS DE REVIEW

                                // for($i = 0; $i < count($oPassenger); $i++){
                                //  for($h = 0; $h < count($oQuestion); $h++){
                                //      $oParam         = array(    $oPassenger[$i]->Id_Passenger,
                                //                                  $oTour[$j]->Id_Tour,
                                //                                  $oQuestion[$h]->Id_Question
                                //                              );

                                //      $oData_Review   = DB::select('call sp_passenger_review_insert(?,?,?)',$oParam);
                                //  }
                                // }

                                // //endregion

                            } catch (Throwable $th) {
                            }
                        }

                        //endregion

                        //region INVOICE

                        for ($i = 0; $i < count($oPassenger); $i++) {
                            $oParam         = array(
                                $Id_Booking,
                                $oPassenger[$i]->Id_Passenger,
                                1
                            );

                            $oData_Invoice  = DB::select('call sp_invoice_insert(?,?,?)', $oParam);


                            $oData          = $oData_Invoice;
                            if ($oDataCashMovement != null) {
                                DB::select('call sp_cash_movement_detail_insert(?,?,?,?,?)', [
                                    $oBooking[$k]->CashMovementDetail_Amount / count($oPassenger),
                                    $oDataCashMovement[0]->Id_CashMovement,
                                    $oData_Invoice[0]->Response_Id,
                                    1,
                                    1
                                ]);
                                $this->passengerUpdater->updateLockHtlCampBookingPassenger($oPassenger[$i]->Id_Passenger);
                            }
                        }

                        //endregion

                        try {
                            BookingMailSender::sendBookingByMail($Id_Booking, $this->oDomain, BookingMailSender::REGULAR_AND_PAYMENT);
                        } catch (\Throwable $ex) {
                        }
                    } else {
                        $oData = $oData_Booking;
                        break;
                    }
                }
            } else {
                $oData = $oDataCashMovement;
            }

            $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);
    }

    public function Index(Request $Request, $Id_User, $Id)
    {
        $oResponse  = array();

        $oResponse = ParamsValidator::Validate_Id($Id_User, $this->oDomain);

        if ($oResponse["Response_Code"] == 200) {
            $oResponse = ParamsValidator::Validate_Id($Id, $this->oDomain);

            if ($oResponse["Response_Code"] == 200) {
                $oParam             = array($Id, $Id_User);
                $oData              = DB::select('call sp_client_booking_index(?,?)', $oParam);

                $Path_ImgDocument1_Thumb    = config("var.PATH_PUBLIC") . config("var.PASSENGER_IMGDOCUMENT1_THUMB");
                $Path_ImgDocument1_Large    = config("var.PATH_PUBLIC") . config("var.PASSENGER_IMGDOCUMENT1_LARGE");
                $Path_ImgDocument2_Thumb    = config("var.PATH_PUBLIC") . config("var.PASSENGER_IMGDOCUMENT2_THUMB");
                $Path_ImgDocument2_Large    = config("var.PATH_PUBLIC") . config("var.PASSENGER_IMGDOCUMENT2_LARGE");

                $oParam             = array(
                    'all',
                    $oData[0]->Id_Booking,
                    $Path_ImgDocument1_Thumb,
                    $Path_ImgDocument1_Large,
                    $Path_ImgDocument2_Thumb,
                    $Path_ImgDocument2_Large
                );

                $oData_Passenger    = DB::select('call sp_client_passenger_list(?,?,?,?,?,?)', $oParam);

                $oParam             = array($oData[0]->Id_Booking);
                $oData_Invoice      = DB::select('call sp_client_invoice_list(?)', $oParam);

                $Response_Data = array(
                    "Id_Booking"            => $oData[0]->Id_Booking,
                    "Booking_Date"          => $oData[0]->Booking_Date,
                    "Booking_DateStart"     => $oData[0]->Booking_DateStart,
                    "Booking_DateBriefing"  => $oData[0]->Booking_DateBriefing,
                    "Booking_Code"          => $oData[0]->Booking_Code,
                    "Booking_Status"        => $oData[0]->Booking_Status,
                    "Booking_Passenger"     => $oData_Passenger,
                    "Booking_Invoice"       => $oData_Invoice,
                    "Id_User"               => $oData[0]->Id_User,
                    "Id_Language"           => $oData[0]->Id_Language,
                    "Language_Code"         => $oData[0]->Language_Code,
                    "Language_Name"         => $oData[0]->Language_Name
                );

                $oResponse["Response_Status"]           = 200;
                $oResponse["Response_Code"]             = 200;
                $oResponse["Response_Domain"]           = $this->oDomain;
                $oResponse["Response_Message"]          = $this->oDomain . " list";
                $oResponse["Response_Data"]             = $Response_Data;
                $oResponse["Response_Error_Message"]    = "";
                $oResponse["Response_Error_Reason"]     = "";
            }
        }

        return ResponseBuilder::Response($oResponse);
    }

    public function List(Request $Request, $Id_User)
    {
        $oResponse  = array();

        $oResponse = ParamsValidator::Validate_Id($Id_User, $this->oDomain);

        if ($oResponse["Response_Code"] == 200) {
            $params = [
                'Booking_Code' => 'string|max:100',
                'Booking_DateStart' => 'required|string',
                'Booking_DateEnd' => 'required|string'
            ];
            $oResponse = ParamsValidator::Validate_Request($Request, $params, $this->oDomain);

            if ($oResponse['Response_Code'] == 200) {
                $oParam     = [
                    $Id_User,
                    $Request->input('Booking_Code'),
                    $Request->input('Booking_DateStart'),
                    $Request->input('Booking_DateEnd'),
                ];
                $oData      = DB::select('call sp_client_booking_list(?,?,?,?)', $oParam);

                $oResponse["Response_Status"]           = 200;
                $oResponse["Response_Code"]             = 200;
                $oResponse["Response_Domain"]           = $this->oDomain;
                $oResponse["Response_Message"]          = $this->oDomain . " list";
                $oResponse["Response_Data"]             = $oData;
                $oResponse["Response_Error_Message"]    = "";
                $oResponse["Response_Error_Reason"]     = "";
            }
        }

        return ResponseBuilder::Response($oResponse);
    }

    public function Report(Request $Request, $Id_User)
    {
        $oResponse  = array();

        $oResponse = ParamsValidator::Validate_Id($Id_User, $this->oDomain);

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

            $oData = self::mapBooking(self::filterAvailableBookings(DB::select('call sp_client_booking_list_report(?)', [$Id_User])));

            $oResponse["Response_Status"]           = 200;
            $oResponse["Response_Code"]             = 200;
            $oResponse["Response_Domain"]           = $this->oDomain;
            $oResponse["Response_Message"]          = $this->oDomain . " list";
            $oResponse["Response_Data"]             = $oData;
            $oResponse["Response_Error_Message"]    = "";
            $oResponse["Response_Error_Reason"]     = "";
        }

        return ResponseBuilder::Response($oResponse);
    }

    public function ReportPdf(Request $Request, $Id_User, $Id_Booking)
    {
        $oResponse  = array();

        $oResponse = ParamsValidator::Validate_Id($Id_User, $this->oDomain);

        if ($oResponse["Response_Code"] != 200) {
            return ResponseBuilder::Response($oResponse);
        }

        $oResponse = ParamsValidator::Validate_Id($Id_Booking, $this->oDomain);

        if ($oResponse['Response_Code'] != 200) {
            return ResponseBuilder::Response($oResponse);
        }

        $invoiceListJSON = json_encode(BookingMailSender::GetInvoiceList($Id_Booking));
        $oBooking = Owner_Booking::getReportData($Id_Booking, $invoiceListJSON);

        $oResponse["Response_Status"]           = 200;
        $oResponse["Response_Code"]             = 200;
        $oResponse["Response_Domain"]           = $this->oDomain;
        $oResponse["Response_Message"]          = $this->oDomain . " list";
        $oResponse["Response_Data"]             = $oBooking;
        $oResponse["Response_Error_Message"]    = "";
        $oResponse["Response_Error_Reason"]     = "";

        return ResponseBuilder::Response($oResponse);
    }

    public static function filterAvailableBookings($bookingList)
    {
        return array_values(array_filter($bookingList, function ($booking) {
            return $booking->Booking_Status == 1 || $booking->Booking_Status == 2;
        }));
    }

    public static function mapBooking($bookingList)
    {
        return array_map(function ($booking) {
            $booking->Booking_Invoice = DB::select('call sp_client_invoice_list(?)', [$booking->Id_Booking]);
            return $booking;
        }, $bookingList);
    }
}
