<?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\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 = "Booking Extra Passenger";
        $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"));

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

    public function Delete(Request $Request, $Id)
    {
        (new LaravelValidator)->validate($Request->all(), $this->oDomain, BookingExtraPassengerValidators::DELETE);
        $oResponse  = array();

        // VALIDANDO DATOS
        $oResponse = ParamsValidator::Validate_Id($Id, $this->oDomain);
        $generateMore = $Request->input('Generate_More');
        $more = $Request->input('InvoiceDetail_Price');
        $description = $Request->input('InvoiceDetail_Description');

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            $this->history->obtainOld($Id);
            $idBooking = $this->findBooking($Id);

            $oData_ExtraPax     = DB::select('call sp_booking_extra_passenger_index(?)', [$Id]);

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

            $this->queryBus->ask(new DeleteBookingAdditionalQuery(BookingAdditionalType::BOOKING_EXTRA_PASSENGER, $Id));
            $oParam             = array($Id, $Request->input('Keep_InvoiceDetail'));
            $oData              = DB::select('call sp_booking_extra_passenger_delete(?,?)', $oParam);

            //  RESPONSE
            if ($oData[0]->Response_Success == 1) {
                $this->history->delete(
                    $idBooking,
                    $this->history->oldValue,
                    $Request
                );
            }

            $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)
    {
        $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)
    {
        $oResponse  = array();

        $oValParams = [
            'Sort_By' => 'required|string|max:50',
            'Search_DateStart' => 'required|string|date',
            'Search_DateEnd' => 'required|string|date',
            'Id_Extra' => 'required|int'
        ];


        // 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"),
                $Request->input("Id_Extra")
            ];
            $oData  = DB::select('call sp_booking_extra_passenger_search(?,?,?,?)', $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 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'
        ];

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

        if ($oResponse["Response_Code"] == 200) {
            $oParam = array(
                $Request->input('Sort_By'),
                $Request->input("Search_DateStart"),
                $Request->input("Search_DateEnd"),
                $Request->input("Id_Extra")
            );

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