<?php

namespace App\Http\Controllers\Owner;

use App\Http\Controllers\Controller;
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\BookingAdditional\Application\CreateFromBookingUpgradePassenger\CreateFromBookingUpgradePassengerBookingAdditionalQuery;
use App\Modules\BookingAdditional\Application\Delete\DeleteBookingAdditionalQuery;
use App\Modules\BookingAdditional\Domain\BookingAdditionalType;
use App\Modules\BookingUpgradePassenger\Application\Remove\RemoveBookingUpgradePassengerQuery;
use App\Modules\BookingUpgradePassenger\Application\Remove\RemoveBookingUpgradePassengerResponse;
use App\Modules\BookingUpgradePassenger\Infrastructure\BookingUpgradePassengerValidators;
use App\Modules\Shared\Application\ActionHandler;
use App\Modules\Shared\Domain\Bus\Query\QueryBus;
use App\Modules\Shared\Domain\GenerateActionException;
use App\Modules\Shared\Validator\Infraestructure\LaravelValidator;
use App\Providers\ExcelTrainsReport\ExcelTrainsReport;
use Illuminate\Support\Facades\DB;

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

    public function __construct(
        private QueryBus $queryBus,
        private PassengerUpdater $passengerUpdater,
    ) {
        $this->oDomain = "Booking Upgrade Passenger";
        $this->history = new HistoryData(HistoryTables::BOOKING_UPGRADE_PASSENGER);
    }

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

    public function Insert_All(Request $Request)
    {
        $oSucces    = true;
        $oResponse  = array();
        $oValParams = array(
            'Id_BookingUpgrade' => '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_Upgrade::findBooking($Request->input('Id_BookingUpgrade'));

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

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

            foreach ($oPassenger as $passenger) {
                $oParam = array(
                    $passenger->BookingUpgradePassenger_DateEntry,
                    $passenger->BookingUpgradePassenger_Datereturn,
                    $Request->input("Id_BookingUpgrade"),
                    $passenger->Id_BookingTourPassenger,
                    1
                );
                $oData = DB::select('call sp_booking_upgrade_passenger_insert_dates(?,?,?,?,?)', $oParam);

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

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

                $this->history->insert(
                    [[
                        'Id_BookingUpgrade' => $Request->input("Id_BookingUpgrade"),
                        'Id_BookingTourPassenger' => $passenger->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_BookingUpgrade'         => '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_Upgrade::findBooking($Request->input('Id_BookingUpgrade'));

            $oParam = [
                $Request->input("Id_BookingUpgrade"),
                $Request->input("Id_BookingTourPassenger"),
                1
            ];
            $oData = DB::select('call sp_booking_upgrade_passenger_insert(?,?,?)', $oParam);
            $data = null;

            if ($oData[0]->Response_Success == 1) {
                $this->history->insert(
                    [$Request->all()],
                    $Request,
                    $Id_Booking
                );
                $data = ['Id' => $oData[0]->Response_Id];
            } 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"]             = $data;
            $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)
    {
        (new LaravelValidator())->validate(
            $Request->all(),
            $this->oDomain,
            BookingUpgradePassengerValidators::UPDATE
        );

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

        $oParam = array(
            $Request->input("BookingUpgradePassenger_OnlyReturn"),
            $Request->input("BookingUpgradePassenger_DateEntry") . ':00',
            $Request->input("BookingUpgradePassenger_Datereturn") . ':00',
            $Request->input("BookingUpgradePassenger_DatePurchase") . ':00',
            $Request->input("BookingUpgradePassenger_Carrier"),
            $Request->input("BookingUpgradePassenger_Code"),
            $Request->input("BookingUpgradePassenger_Amount"),
            $Request->input("BookingUpgradePassenger_RoundCarrier"),
            $Request->input("BookingUpgradePassenger_RoundCode"),
            $Request->input("BookingUpgradePassenger_RoundAmount"),
            $Request->input("BookingUpgradePassenger_Remark"),
            $Request->header("Token"),
            $Request->input('Id_Provider', 0),
            $Request->input('Id_Provider_Return', 0),
            $Request->input("Id_BookingUpgradePassenger")
        );
        $oData = DB::select('call sp_booking_upgrade_passenger_update(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', $oParam);
        if ($oData[0]->Response_Success == 1) {
            $this->history->update(
                $this->findBooking($Request->input("Id_BookingUpgradePassenger")),
                $this->history->oldValue,
                [$Request->all()],
                $Request
            );
        }

        $oResponse = [];
        $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 simpleUpdate(Request $request)
    {
        (new LaravelValidator())->validate(
            $request->all(),
            $this->oDomain,
            BookingUpgradePassengerValidators::SIMPLE_UPDATE
        );

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

        $index = DB::select('call sp_booking_upgrade_passenger_index(?)', [$request->input("Id_BookingUpgradePassenger")]);
        if ($this->isTicketBuyed($index)) {
            (new GenerateActionException())->__invoke('Ticket de pasajero no se puede modificar por estar comprado.');
        }

        $oParam = [
            $request->input("Id_BookingUpgradePassenger"),
            $request->input("BookingUpgradePassenger_DateEntry"),
            $request->input("BookingUpgradePassenger_Datereturn"),
        ];
        $oData = DB::select('call sp_booking_upgrade_passenger_simple_update(?,?,?)', $oParam);

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

        if ($oData[0]->Response_Success == 1) {
            $this->history->update(
                $this->findBooking($request->input("Id_BookingUpgradePassenger")),
                $this->history->oldValue,
                [$request->all()],
                $request
            );
        }

        $oResponse = [];
        $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 UpdateDateEntry(Request $Request)
    {
        $oResponse  = array();
        $oValParams = array(
            'BookingUpgradePassenger_DateEntry'         => 'required|string',
            'Id_BookingUpgradePassenger'                => '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_BookingUpgradePassenger'));

            $oParam = array(
                $Request->input("BookingUpgradePassenger_DateEntry"),
                $Request->input("Id_BookingUpgradePassenger")
            );
            $oData = DB::select('call sp_booking_upgrade_passenger_update_date_entry(?,?)', $oParam);

            if ($oData[0]->Response_Success == 1) {
                $this->history->update(
                    $this->findBooking($Request->input("Id_BookingUpgradePassenger")),
                    $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]->BookingUpgradePassenger_Status === 2;
    }

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

        $this->history->obtainOld($Id);

        $idBooking = $this->findBooking($Id);
        $index     = DB::select('call sp_booking_upgrade_passenger_index(?)', [$Id]);

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

        $this->queryBus->ask(new DeleteBookingAdditionalQuery(BookingAdditionalType::BOOKING_UPGRADE_PASSENGER, $Id));
        /** @var RemoveBookingUpgradePassengerResponse $response */
        $response = $this->queryBus->ask(new RemoveBookingUpgradePassengerQuery($Id, $Request->input('Keep_InvoiceDetail')));

        $this->history->delete($idBooking, $this->history->oldValue, $Request);
        return ResponseBuilder::Response($response->response());
    }

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

        // VALIDANDO DATOS
        $oResponse = ParamsValidator::Validate_Id($Id, $this->oDomain);

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            $oParam = array($Id);
            $oData  = DB::select('call sp_booking_upgrade_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_BookingUpgrade)
    {
        $oResponse  = array();

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

        if ($oResponse["Response_Code"] == 200) {
            $oParam = array($Id_BookingUpgrade, 0);
            $oData  = DB::select('call sp_booking_upgrade_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_Upgrade'       => '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_Upgrade'),
            (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_upgrade_passenger_search(?,?,?,?,?,?,?,?,?,?,?)', [...$filterParams, $limit, $offset]);
        $count = DB::select('call sp_booking_upgrade_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_Upgrade'       => '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_Upgrade'),
                (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_upgrade_passenger_search(?,?,?,?,?,?,?,?,?,?,?)', $oParam);

            (new ExcelTrainsReport())->exportToExcel([(object)['Upgrade' => $oData]]);
        } else {
            return ResponseBuilder::Response($oResponse);
        }
    }
}
