<?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\BookingEquipment\Application\BookingEquipmentPassengerList;
use App\Modules\BookingEquipment\Application\CanDelete\CanDeleteBookingEquipmentQuery;
use App\Modules\BookingEquipment\Application\CanDelete\CanDeleteBookingEquipmentResponse;
use App\Modules\BookingEquipment\Infraestructure\MysqlBookingEquipmentRepository;
use App\Modules\BookingEquipmentPassenger\Application\BookingEquipmentPassengerResponses;
use App\Modules\BookingEquipmentPassenger\Application\List\ListBookingEquipmentPassengerQuery;
use App\Modules\Shared\Domain\Bus\Query\QueryBus;
use App\Modules\Shared\Domain\Data\DataGroupMap;
use App\Modules\Shared\Exceptions\InvalidRequestException;
use Illuminate\Support\Facades\DB;

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

    public function __construct(
        private QueryBus $queryBus,
        private PassengerUpdater $passengerUpdater,
    ) {
        $this->oDomain = "Booking Equipment";
        $this->history = new HistoryData(HistoryTables::booking_equipment);
        $this->historyPassengers = new HistoryData(HistoryTables::booking_equipment_passenger);
    }

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

    public function Insert(Request $Request)
    {
        $oSucces    = true;
        $oResponse  = array();
        $oValParams = array(
            'BookingEquipment_Quantity' => 'required|int',
            'BookingEquipment_Mode'     => 'int',
            'Id_BookingTour'            => 'required|int',
            'Id_Equipment'              => 'required|int',
            'Passenger'                 => 'required|string'
        );


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

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            $oParam =   [
                $Request->input("BookingEquipment_Quantity"),
                2,
                1,
                $Request->input("BookingEquipment_Mode", 1),
                $Request->input("Id_BookingTour"),
                $Request->input("Id_Equipment"),
                1,
                1
            ];
            $oData = DB::select('call sp_booking_equipment_insert(?,?,?,?,?,?,?,?)', $oParam);

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

                $this->history->insert(
                    [$Request->all()],
                    $Request,
                    BookingTour::findBooking($Request->input('Id_BookingTour'))
                );

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

                for ($k = 0; $k < count($oPassenger); $k++) {
                    $oParam = array(
                        $oData[0]->Response_Id,
                        $oPassenger[$k]->Id_BookingTourPassenger,
                        1,
                        $Request->header("Token"),
                    );
                    $oDataPax = DB::select('call sp_booking_equipment_passenger_insert(?,?,?,?)', $oParam);

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

                    $this->historyPassengers->insert(
                        [
                            'Id_BookingEquipment' => $oData[0]->Response_Id,
                            'Id_BookingTourPassenger' => $oPassenger[$k]->Id_BookingTourPassenger,
                        ],
                        $Request,
                        BookingTour::findBooking($Request->input('Id_BookingTour'))
                    );
                }

                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));
                }
            } 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 function Update(Request $Request)
    {
        $oResponse  = array();
        $oValParams = array(
            'Id_BookingEquipment'       => 'required|int',
            'BookingEquipment_Included' => 'required|int',
            'BookingEquipment_Mode'     => 'required|int',
            'Id_BookingTour'            => 'required|int',
            'Id_Equipment'              => '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_BookingEquipment'));

            $oParam = array(
                $Request->input("Id_BookingEquipment"),
                2,
                $Request->input("BookingEquipment_Included"),
                $Request->input("BookingEquipment_Mode"),
                $Request->input("Id_BookingTour"),
                $Request->input("Id_Equipment"),
                1
            );
            $oData = DB::select('call sp_booking_equipment_update(?,?,?,?,?,?,?)', $oParam);

            //  RESPONSE
            if ($oData[0]->Response_Success == 1) {
                $bup = DB::select('call sp_booking_equipment_passenger_list(?,?)', [$Request->input('Id_BookingEquipment'), 0]);
                foreach ($bup as $item) {
                    DB::select('call sp_invoice_reload(?, ?)', [$item->Id_Passenger, 1]);
                    $this->passengerUpdater->updateLockHtlCampBookingPassenger($item->Id_Passenger);
                }
                $this->history->update(
                    $this->findBooking($Request->input('Id_BookingEquipment')),
                    $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 function Delete(Request $Request, $Id)
    {
        $oResponse  = array();

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

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

            /** @var CanDeleteBookingEquipmentResponse $canDeleteResponse  */
            $canDeleteResponse = $this->queryBus->ask(new CanDeleteBookingEquipmentQuery($Id));

            if (!$canDeleteResponse->value) {
                throw new InvalidRequestException('No se puede eliminar el equipamiento');
            }

            /** @var BookingEquipmentPassengerResponses $bepsResponse */
            $bepsResponse = $this->queryBus->ask(new ListBookingEquipmentPassengerQuery(null, [$Id]));
            foreach ($bepsResponse->data() as $bep) {
                c_Booking_Equipment_Passenger::removeBookingEquipmentPassenger($bep->Id_BookingEquipmentPassenger, 1, $Request);
            }

            $oParam = array($Id);
            $oData  = DB::select('call sp_booking_equipment_delete(?)', $oParam);

            //  RESPONSE
            if ($oData[0]->Response_Success == 1) {
                $this->history->delete(
                    $this->findBooking($Id),
                    $this->history->oldValue,
                    $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 function Index(Request $Request, $Id)
    {
        $oResponse  = array();

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

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            $oParam = array($Id);
            $data  = DB::select('call sp_booking_equipment_index(?)', $oParam);
            $data = $this->richBookingEquipment($data);

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

        return ResponseBuilder::Response($oResponse);
    }

    private function richBookingEquipment(
        $bookingEquipments
    ) {
        $list = array_map([$this, 'richEquipment'], $bookingEquipments);
        $ids = array_map(fn($item) => $item->id, $list);

        /** @var stdClass $response */
        $response = $this->queryBus->ask(new ListBookingEquipmentPassengerQuery(null, $ids));
        $map = new DataGroupMap($response->data(), 'Id_BookingEquipment');

        foreach ($list as $key => $item) {
            $list[$key]->passengers = $map->get($item->id) ?? [];
        }
        return $list;
    }

    private function richEquipment($model)
    {
        $model->id = $model->Id_BookingEquipment;
        $model->cant = $model->BookingEquipment_Quantity;
        $model->price = $model->BookingEquipment_Price;
        $model->total = $model->BookingEquipment_Total;
        $model->show = $model->BookingEquipment_Show;
        $model->mode = $model->BookingEquipment_Mode;
        $model->included = $model->BookingEquipment_Included;
        $model->name = $model->Item_Name;
        $model->type = 3;
        $model->status = $model->BookingEquipment_Status;
        return $model;
    }

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

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

        if ($oResponse["Response_Code"] == 200) {
            $oParam = array($Id_BookingTour);
            $oData  = DB::select('call sp_booking_equipment_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 PassengerList(Request $Request, $Id_BookingTour, $Action)
    {
        $oResponse = (new BookingEquipmentPassengerList(new MysqlBookingEquipmentRepository))->__invoke($Action, $Id_BookingTour);
        return ResponseBuilder::Response($oResponse);
    }
}
