<?php

namespace App\Http\Controllers\Owner;

use App\Http\Controllers\Controller;
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\BookingAdditional\Application\CreateFromBookingExtraPassenger\CreateFromBookingExtraPassengerBookingAdditionalQuery;
use App\Modules\BookingAdditional\Application\Delete\DeleteBookingAdditionalQuery;
use App\Modules\BookingAdditional\Domain\BookingAdditionalType;
use App\Modules\BookingExtraPassenger\Infrastructure\BookingExtraPassengerValidators;
use App\Modules\Room\Application\Index\IndexRoomQuery;
use App\Modules\Room\Application\ReloadPassengerAmount\ReloadPassengerAmountRoomQuery;
use App\Modules\Room\Application\RoomResponse;
use App\Modules\RoomPassenger\Application\Delete\DeleteRoomPassengerQuery;
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 App\Modules\Shared\Infraestructure\Requester;
use App\Modules\Shared\Validator\Infraestructure\LaravelValidator;
use App\Providers\ExcelEntrancesReport\ExcelEntrancesReport;
use Illuminate\Support\Facades\DB;

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

    public function __construct(
        private EventBus $eventBus,
        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 Insert_All(Request $Request)
    {
        $oSucces    = true;
        $oResponse  = array();
        $oValParams = array(
            'Id_BookingExtra'   => 'required|int',
            'Passenger'         => 'required|string'
        );

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

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

            $Id_Booking = c_Booking_Extra::findBooking($Request->input('Id_BookingExtra'));

            $oPassenger = json_decode($Request->input("Passenger"));

            foreach ($oPassenger as $passenger) {
                $oValParams = [
                    'BookingExtraPassenger_DateEntryStart' => 'required|date',
                    'BookingExtraPassenger_DateEntryEnd' => 'required|date'
                ];
                $value = [
                    'BookingExtraPassenger_DateEntryStart' => $passenger->BookingExtraPassenger_DateEntryStart,
                    'BookingExtraPassenger_DateEntryEnd' => $passenger->BookingExtraPassenger_DateEntryEnd,
                    'Id_BookingTourPassenger' => $passenger->Id_BookingTourPassenger,
                ];
                (new LaravelValidator())->validate($value, $this->oDomain, $oValParams);
            }

            for ($k = 0; $k < count($oPassenger); $k++) {
                $oParam = array(
                    $oPassenger[$k]->BookingExtraPassenger_DateEntryStart,
                    $oPassenger[$k]->BookingExtraPassenger_DateEntryEnd,
                    $Request->input("Id_BookingExtra"),
                    $oPassenger[$k]->Id_BookingTourPassenger,
                    1
                );
                $oData = DB::select('call sp_booking_extra_passenger_insert_dates(?,?,?,?,?)', $oParam);

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

                $this->queryBus->ask(new CreateFromBookingExtraPassengerBookingAdditionalQuery($oData[0]->Response_Id));

                $this->history->insert(
                    [[
                        'Id_BookingExtra' => $Request->input("Id_BookingExtra"),
                        'Id_BookingTourPassenger' => $oPassenger[$k]->Id_BookingTourPassenger
                    ]],
                    $Request,
                    $Id_Booking
                );
            }

            if ($oSucces == true) {
                $oData = array(
                    array(
                        "Response_Status"   => 200,
                        "Response_Code"     => 200,
                        "Response_Message"  => "Pasajeros guardados con éxito",
                        "Response_Reason"   => null
                    )
                );

                $oData = json_decode(json_encode($oData));
            }

            $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 Insert(Request $Request)
    {
        $oResponse  = array();
        $oValParams = array(
            'Id_BookingExtra'           => 'required|int',
            'Id_BookingTourPassenger'   => 'required|int'
        );

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

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            $Id_Booking = c_Booking_Extra::findBooking($Request->input('Id_BookingExtra'));

            $oParam = array(
                $Request->input("Id_BookingExtra"),
                $Request->input("Id_BookingTourPassenger"),
                1
            );
            $oData = DB::select('call sp_booking_extra_passenger_insert(?,?,?)', $oParam);

            if ($oData[0]->Response_Success == 1) {
                $this->queryBus->ask(new CreateFromBookingExtraPassengerBookingAdditionalQuery($oData[0]->Response_Id));
                $this->history->insert(
                    [$Request->all()],
                    $Request,
                    $Id_Booking
                );
            }

            $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 Update(Request $Request)
    {
        $oResponse  = array();
        $oValParams = array(
            'BookingExtraPassenger_DateEntryStart'  => 'required|string',
            'BookingExtraPassenger_HourEntryStart'  => 'required|string',
            'BookingExtraPassenger_HourEntryEnd'    => 'required|string',
            'BookingExtraPassenger_DatePurchase'    => 'required|string',
            'BookingExtraPassenger_Code'            => 'required|string',
            'BookingExtraPassenger_Amount'          => 'required|numeric',
            'BookingExtraPassenger_Remark'          => 'string',
            'Id_BookingExtraPassenger'              => 'required|int'
        );


        // VALIDANDO DATOS
        (new LaravelValidator)->validate($Request->all(), $this->oDomain, $oValParams);

        //  INGRESANDO DATOS

        $this->history->obtainOld($Request->input("Id_BookingExtraPassenger"));

        $oParam = array(
            $Request->input("BookingExtraPassenger_DateEntryStart") . ' ' . $Request->input("BookingExtraPassenger_HourEntryStart") . ':00',
            $Request->input("BookingExtraPassenger_DateEntryStart") . ' ' . $Request->input("BookingExtraPassenger_HourEntryEnd") . ':00',
            $Request->input('BookingExtraPassenger_DatePurchase'),
            $Request->input("BookingExtraPassenger_Code"),
            $Request->input("BookingExtraPassenger_Amount"),
            $Request->input("BookingExtraPassenger_Remark"),
            $Request->header("Token"),
            $Request->input("Id_CommercialInvoice", 0),
            $Request->input("Id_BookingExtraPassenger")
        );
        $oData = (new ActionHandler())->handle(DB::select('call sp_booking_extra_passenger_update(?,?,?,?,?,?,?,?,?)', $oParam));

        $this->history->update(
            $this->findBooking($Request->input("Id_BookingExtraPassenger")),
            $this->history->oldValue,
            [$Request->all()],
            $Request
        );

        return ResponseBuilder::Response(Requester::generateResponse($oData, $this->oDomain));
    }

    public function simpleUpdate(Request $request)
    {
        $oResponse  = array();
        $oValParams = [
            'BookingExtraPassenger_DateEntryStart'  => 'required|string',
            'BookingExtraPassenger_DateEntryEnd'    => 'required|string',
            'Id_BookingExtraPassenger'              => 'required|int'
        ];


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

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

            $this->history->obtainOld($request->input("Id_BookingExtraPassenger"));

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

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

                /** @var RoomPassengerResponses $response */
                $response = $this->queryBus->ask(new ListRoomPassengerQuery(
                    'all',
                    idBookingExtraPassenger: $request->input("Id_BookingExtraPassenger"),
                    idRoom: null,
                ));

                $rooms = [];
                foreach ($response->data() as $roomPassenger) {
                    if (isset($rooms[$roomPassenger->Id_Room])) {
                        continue;
                    }
                    $rooms[$roomPassenger->Id_Room] = true;
                    $this->queryBus->ask(new ReloadPassengerAmountRoomQuery($roomPassenger->Id_Room));
                }

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

    public static function getIndex($id)
    {
        return DB::select('call sp_booking_extra_passenger_index(?)', [$id]);
    }

    public function Index(Request $Request, $Id)
    {
        $oResponse  = array();
        $oResponse = ParamsValidator::Validate_Id($Id, $this->oDomain);

        if ($oResponse["Response_Code"] == 200) {
            $oParam = array($Id);
            $oData  = DB::select('call sp_booking_extra_passenger_index(?)', $oParam);
            if (count($oData) > 0) {
                $oData[0]->UserCountry_Img_Thumb = config('var.PATH_PUBLIC')
                    . config('var.USER_COUNTRY_THUMB')
                    . $oData[0]->UserCountry_Img;
            }

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

        return ResponseBuilder::Response($oResponse);
    }

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

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

        if ($oResponse["Response_Code"] == 200) {
            $oParam = [$Id_BookingExtra, 0];
            $oData  = DB::select('call sp_booking_extra_passenger_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 Search(Request $Request)
    {
        $oValParams = [
            'Sort_By'          => 'required|string|max:50',
            'Search_DateStart' => 'required|string|date',
            'Search_DateEnd'   => 'required|string|date',
            'Id_Extra'         => 'required|int',
            'Status'           => 'int',
            'Mask'             => 'int',
            'Id_CategoryTour'  => 'int',
            'Id_Tour'          => 'int',
            'Search'           => 'string|max:255',
            'Page'             => 'int',
            'PageSize'         => 'int',
        ];

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

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

        $page   = $Request->input('Page');
        $pgSize = $Request->input('PageSize');
        $limit  = ($page !== null && $pgSize !== null) ? (int) $pgSize : PHP_INT_MAX;
        $offset = ($page !== null && $pgSize !== null) ? ((int) $page - 1) * (int) $pgSize : 0;

        $filterParams = [
            $Request->input('Sort_By'),
            $Request->input('Search_DateStart'),
            $Request->input('Search_DateEnd'),
            (int) $Request->input('Id_Extra'),
            (int) $Request->input('Status', 0),
            (int) $Request->input('Mask', 0),
            (int) $Request->input('Id_CategoryTour', 0),
            (int) $Request->input('Id_Tour', 0),
            $Request->input('Search') ?: null,
        ];

        $oData = DB::select('call sp_booking_extra_passenger_search(?,?,?,?,?,?,?,?,?,?,?)', [...$filterParams, $limit, $offset]);
        $count = DB::select('call sp_booking_extra_passenger_search_count(?,?,?,?,?,?,?,?,?)', $filterParams);

        return ResponseBuilder::Response(
            ResponseBuilder::buildSelectResponse($oData, $this->oDomain . ' Search', $this->oDomain, $count[0]->total ?? 0)
        );
    }

    public function ExportExcel(Request $Request)
    {
        $oResponse  = array();

        $oValParams = [
            'Sort_By'          => 'required|string|max:100',
            'Search_DateStart' => 'required|string|date',
            'Search_DateEnd'   => 'required|string|date',
            'Id_Extra'         => 'required|int',
            'Status'           => 'int',
            'Mask'             => 'int',
            'Id_CategoryTour'  => 'int',
            'Id_Tour'          => 'int',
            'Search'           => 'string|max:255',
        ];

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

        if ($oResponse["Response_Code"] == 200) {
            $oParam = [
                $Request->input('Sort_By'),
                $Request->input('Search_DateStart'),
                $Request->input('Search_DateEnd'),
                (int) $Request->input('Id_Extra'),
                (int) $Request->input('Status', 0),
                (int) $Request->input('Mask', 0),
                (int) $Request->input('Id_CategoryTour', 0),
                (int) $Request->input('Id_Tour', 0),
                $Request->input('Search') ?: null,
                PHP_INT_MAX,
                0,
            ];

            $oData  = DB::select('call sp_booking_extra_passenger_search(?,?,?,?,?,?,?,?,?,?,?)', $oParam);
            (new ExcelEntrancesReport())->exportToExcel([(object)['Extra' => $oData]]);
        } else {
            return ResponseBuilder::Response($oResponse);
        }
    }
}
