<?php

/**
 * MyClass Class Doc Comment
 * php version 8.0.1
 *
 * @category Class
 * @package  App\Http\Controllers\Owner
 * @author   Salkantay Treking <developer@salkantaytrekking.com>
 * @license  http://www.gnu.org/copyleft/gpl.html GNU General Public License
 * @link     http://www.hashbangcode.com/
 */

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\Providers\ExcelGroupReport\ExcelGroupReport;
use App\Providers\ExcelGroupResumeReport\ExcelGroupResumeReport;
use App\Providers\ExcelGroupReviewsReport\ExcelGroupReviewsReport;
use App\Mail\c_Mail_User;
use Illuminate\Support\Facades\Mail;
use App\Http\History\HistoryData;
use App\Http\History\HistoryTables;
use App\Modules\EmailShip\Application\EmailShipShipper;
use App\Modules\EmailShip\Infraestructure\MysqlEmailShipRepository;
use App\Modules\EmailShip\Infraestructure\MysqlEmailShipShippedRepository;
use App\Modules\Group\Application\GroupSlaveList;
use App\Modules\Group\Application\GroupStatusChanger;
use App\Modules\Group\Application\GroupTokenGetter;
use App\Modules\Group\Application\Report\ReportGroupCounter;
use App\Modules\Group\Application\Report\ReportGroupFinder;
use App\Modules\Group\Application\Report\ReportGroupQuery;
use App\Modules\Group\Application\Report\ReportGroupQueryHandler;
use App\Modules\Group\Application\UpdateDateUpdate\UpdateGroupDateUpdateQuery;
use App\Modules\Group\Domain\GroupStatus;
use App\Modules\Group\Domain\IdGroup;
use App\Modules\Group\Domain\IncludeSelf;
use App\Modules\Group\Infraestructure\GroupValidators;
use App\Modules\Group\Infraestructure\MysqlGroupGetTokenRepository;
use App\Modules\Group\Infraestructure\MysqlGroupSlaveRepository;
use App\Modules\Group\Infraestructure\MysqlGroupStatusRepository;
use App\Modules\Group\Infraestructure\MysqlReportGroupRepository;
use App\Modules\GroupPassenger\Application\UpdateReview\UpdateReviewGroupPassengerQuery;
use App\Modules\GroupPassenger\Domain\GroupPassengerReviewStatus;
use App\Modules\GroupProviderReview\Application\Create\GroupProviderReviewInserterQuery;
use App\Modules\Shared\Domain\Bus\Query\QueryBus;
use App\Modules\Shared\Infraestructure\QueryList\LaravelListValidator;
use App\Modules\Shared\Validator\Infraestructure\LaravelValidator;
use App\Providers\BookingMailSender;
use App\Providers\GroupReports;
use Illuminate\Support\Facades\DB;
use Throwable;

class Group extends Controller
{
    private $oDomain;
    private HistoryData $history;
    private HistoryData $historyGroupPassenger;

    public function __construct(
        private QueryBus $queryBus
    ) {
        $this->oDomain = "Group";
        $this->history = new HistoryData(HistoryTables::GROUP);
        $this->historyGroupPassenger = new HistoryData(HistoryTables::GROUP_PASSENGER);
    }

    private function insertHistory($Request, $Id)
    {
        $this->history->insert(
            [$Request->all()],
            $Request,
            $Id
        );
    }

    public function Insert(Request $Request)
    {
        $oResponse  = array();
        $oValParams = [
            'Group_DateStart'       => 'required|string',
            'Group_Hour'            => 'string',
            'Group_Origin'          => 'string|max:250',
            'Group_Destination'     => 'string|max:250',
            'Group_Type'            => 'required|int',
            'Group_Remark'          => 'string',
            'Group_ServiceType'     => 'required|int',
            'Id_Service'            => 'required|int'
        ];


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

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            $oParam = array(
                $Request->input("Group_DateStart"),
                $Request->input("Group_Hour"),
                $Request->input("Group_Origin"),
                $Request->input("Group_Destination"),
                $Request->input("Group_Type"),
                $Request->input("Group_Remark"),
                $Request->input("Group_ServiceType"),
                $Request->input("Id_Service")
            );
            $oData = DB::select('call sp_group_insert(?,?,?,?,?,?,?,?)', $oParam);

            $data = null;
            //  RESPONSE
            if ($oData[0]->Response_Success == 1) {
                $this->insertHistory($Request, $oData[0]->Response_Id);
                $data = ['Id' => $oData[0]->Response_Id];
            }

            $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 Insert_Full(Request $Request)
    {
        $oSucces    = true;
        $oResponse  = array();
        $oValParams = array(
            'Group_DateStart'       => 'required|string',
            'Group_Hour'            => 'string',
            'Group_Origin'          => 'string|max:250',
            'Group_Destination'     => 'string|max:250',
            'Group_Remark'          => 'string',
            'Id_Service'            => 'required|int',
            'Passenger'             => 'required|string'
        );


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

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            $oParam = array(
                $Request->input("Group_DateStart"),
                $Request->input("Group_Hour"),
                $Request->input("Group_Origin"),
                $Request->input("Group_Destination"),
                1,
                $Request->input("Group_Remark"),
                2,
                $Request->input("Id_Service")
            );
            $oData = DB::select('call sp_group_insert(?,?,?,?,?,?,?,?)', $oParam);

            //  RESPONSE
            if ($oData[0]->Response_Success == 1) {
                $this->insertHistory($Request, $oData[0]->Response_Id);

                $Id_Group       = $oData[0]->Response_Id;
                $oPassenger     = json_decode($Request->input("Passenger"));

                for ($k = 0; $k < count($oPassenger); $k++) {
                    $oParam = [
                        $oPassenger[$k]->Id_BookingTourPassenger,
                        3,
                        1
                    ];
                    $oData  = DB::select('call sp_booking_tour_passenger_status(?,?,?)', $oParam);
                    if ($oData[0]->Response_Success == 0) {
                        $oSucces = false;
                        break;
                    }
                    $oParam = [
                        1,
                        $Id_Group,
                        $oPassenger[$k]->Id_BookingTourPassenger
                    ];
                    $oData = DB::select('call sp_group_passenger_insert(?,?,?)', $oParam);

                    if ($oData[0]->Response_Success == 0) {
                        $oSucces = false;
                        break;
                    }
                    $this->historyGroupPassenger->insert(
                        [
                            'GroupPassenger_Type' => 1,
                            'Id_Group' => $Id_Group,
                            'Id' => $oPassenger[$k]->Id_BookingTourPassenger
                        ],
                        $Request,
                        $Id_Group
                    );
                }

                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 = [
            'Id_Group'          => 'required|int',
            'Group_DateStart'   => 'required|string',
            'Group_Hour'        => 'string',
            'Group_Origin'      => 'string|max:250',
            'Group_Destination' => 'string|max:250',
            'Group_Type'        => 'required|int',
            'Id_Service'        => '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_Group'));

            $oParam = array(
                $Request->input("Id_Group"),
                $Request->input("Group_DateStart"),
                $Request->input("Group_Hour"),
                $Request->input("Group_Origin"),
                $Request->input("Group_Destination"),
                $Request->input("Group_Type"),
                $Request->input("Id_Service")
            );
            $oData = DB::select('call sp_group_update(?,?,?,?,?,?,?)', $oParam);

            //  RESPONSE
            if ($oData[0]->Response_Success == 1) {
                $this->history->update(
                    $Request->input('Id_Group'),
                    $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 Remark(Request $Request)
    {
        $oResponse  = array();
        $oValParams = array(
            'Id_Group'          => 'required|int',
            'Group_Remark'      => 'required|string'
        );


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

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

            $oParam = [
                $Request->input("Id_Group"),
                $Request->input("Group_Remark")
            ];
            $oData = DB::select('call sp_group_remark(?,?)', $oParam);

            //  RESPONSE
            if ($oData[0]->Response_Success == 1) {
                $this->queryBus->ask(new UpdateGroupDateUpdateQuery($Request->input('Id_Group')));
                $this->history->update(
                    $Request->input('Id_Group'),
                    $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 GenerateReviewLink(Request $Request)
    {
        $oResponse  = array();
        $oValParams = [
            'Id_Group' => 'required|int'
        ];

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

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            $credentialList = BookingMailSender::getCredentialList();
            $resource = BookingMailSender::filterCredential($credentialList, 'Web_URL');

            $encrypter = (new GroupTokenGetter(new MysqlGroupGetTokenRepository))->__invoke(new IdGroup($Request->input('Id_Group')));

            $oResponse["Response_Status"]           = 200;
            $oResponse["Response_Code"]             = 200;
            $oResponse["Response_Domain"]           = $this->oDomain;
            $oResponse["Response_Message"]          = 'Link generado con éxito';
            $oResponse["Response_Data"]             = ['Url' => $resource[0]->Credential_Value . 'group-review/' . $encrypter[0]->Group_Token];
            $oResponse["Response_Error_Message"]    = '';
            $oResponse["Response_Error_Reason"]     = '';
        }

        return ResponseBuilder::Response($oResponse);
    }

    public function Status(Request $Request)
    {
        $validator = (new LaravelValidator());
        $validator->validate($Request->all(), $this->oDomain, GroupValidators::STATUS);
        $oResponse = array();

        $this->history->obtainOld($Request->input('Id_Group'));

        $idGroup = $Request->input("Id_Group");
        $groupStatus = $Request->input("Group_Status");

        $oData = (new GroupStatusChanger(new MysqlGroupStatusRepository))->__invoke(
            new IdGroup($idGroup),
            new GroupStatus($groupStatus)
        );
        $cantimail = 0;
        $oDataGroup = $this->getGroup($idGroup);
        $responseData = [];
        if ($groupStatus == GroupStatus::CONFIRMED && $oDataGroup[0]->Group_ServiceType == 1) {
            $req = $Request;
            $passengerList = $this->getPassengerList($idGroup, $req->header('token'), $req->ip());
            $groupProviderList = $this->getGroupProviderList($idGroup, $req->header('token'), $req->ip());
            $questionList = $this->getQuestionList($oDataGroup[0]->Id_Service);

            for ($k = 0; $k < count($passengerList); $k++) {
                foreach ($questionList as $question) {
                    if (!$this->questionTypeProviderAvailableFor($question->QuestionTypeProvider, 2, 0)) {
                        continue;
                    }
                    $oParam = [
                        $passengerList[$k]->Id_GroupPassenger,
                        $passengerList[$k]->Id_BookingTourPassenger,
                        $idGroup,
                        $question->Id_Question
                    ];
                    $oData_Review = DB::select('call sp_passenger_review_insert(?,?,?,?)', $oParam);
                }
                $this->queryBus->ask(new UpdateReviewGroupPassengerQuery(
                    $passengerList[$k]->Id_GroupPassenger,
                    GroupPassengerReviewStatus::PENDING
                ));
            }

            if (!config('var.TESTMODE_REVIEWMAIL')) {
                $mailResults = $this->sendMailToPassengers($passengerList);
                $cantimail = count(array_filter($mailResults, fn ($result) => !!$result));
            }

            foreach ($groupProviderList as $groupProvider) {
                foreach ($questionList as $question) {
                    if (!$this->questionTypeProviderAvailableFor($question->QuestionTypeProvider, 1, $groupProvider->Id_TypeProvider)) {
                        continue;
                    }
                    $this->queryBus->ask(
                        new GroupProviderReviewInserterQuery(
                            $groupProvider->Id_GroupProvider,
                            $question->Id_Question
                        )
                    );
                }
            }
        }

        $this->queryBus->ask(new UpdateGroupDateUpdateQuery($idGroup));

        $this->history->update(
            $Request->input('Id_Group'),
            $this->history->oldValue,
            [$Request->all()],
            $Request
        );

        $oData[0]->Response_Message = $oData[0]->Response_Message . '(' . $cantimail . ')';

        return ResponseBuilder::Response(ResponseBuilder::build($oData, null, $this->oDomain));
    }

    private function sendMailToPassengers($passengerList)
    {
        return array_map(fn ($passenger) => $this->sendReviewsMail($passenger), $passengerList);
    }

    private function getQuestionList($idTour)
    {
        return array_map(
            function ($tql) {
                $tql->QuestionTypeProvider = json_decode($tql->QuestionTypeProviderJSON);
                return $tql;
            },
            DB::select('call sp_tour_question_list(?)', [$idTour])
        );
    }

    private function questionTypeProviderAvailableFor(array $questionTypeProviderList, int $questionTypeProviderForPassenger, int $idTypeProvider)
    {
        $show = true;
        foreach ($questionTypeProviderList as $qtp) {
            if ($qtp->QuestionTypeProvider_ForPassenger != $questionTypeProviderForPassenger) {
                continue;
            }

            if ($idTypeProvider == 0) {
                if ($idTypeProvider == $qtp->Id_TypeProvider) {
                    $show = $qtp->QuestionTypeProvider_Show == 2;
                    break;
                } else {
                    $show = true;
                    break;
                }
            } else {
                if ($qtp->Id_TypeProvider == 0) {
                    $show = $qtp->QuestionTypeProvider_Show == 2;
                } else {
                    if ($qtp->Id_TypeProvider == $idTypeProvider) {
                        $show = $qtp->QuestionTypeProvider_Show == 2;
                        break;
                    }
                }
            }
        }
        return $show;
    }

    private function getGroupProviderList($idGroup)
    {
        return DB::select('call sp_group_provider_list(?)', [$idGroup]);
    }

    private function getPassengerList($idGroup, $token, $ip)
    {
        $oParam         = [
            $idGroup
        ];
        return DB::select('call sp_group_passenger_list_review(?)', $oParam);
    }

    private function getGroup($idGroup)
    {
        return DB::select('call sp_group_index(?)', [$idGroup]);
    }

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

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

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

            $Path_Thumb     = config("var.PATH_PUBLIC") . config("var.USER_COUNTRY_THUMB");
            $oParam         = [
                $Id,
                $Path_Thumb,
                $Request->header("Token"),
                $Request->ip()
            ];

            $oData_Passenger = DB::select('call sp_group_passenger_list(?,?,?,?)', $oParam);
            foreach ($oData_Passenger as $pass) {
                if ($pass->Group_ServiceType == 1) {
                    $this->sendReviewsMail($pass);
                }
            }
        }

        return ResponseBuilder::Response($oResponse);
    }

    public function sendReviewsMail($oData_Passenger)
    {
        $Variables              = array(
            "Lang"      => 1,
            "Name"      => $oData_Passenger->Passenger_Name,
            "LastName"  => $oData_Passenger->Passenger_LastName,
            "Token"     => $oData_Passenger->Passenger_Token,
            'WebUrl'    => BookingMailSender::getWebUrl()[0]->Credential_Value,
            'ResourcesUrl'  => BookingMailSender::getResourcesUrl()[0]->Credential_Value
        );

        $oMail_User             = new c_Mail_User;
        $oMail_User->Type       = 2;
        $oMail_User->Subject    = "Your opinion is very useful for us";
        $oMail_User->Content    = $Variables;

        if ($oData_Passenger->Passenger_Email != "" && $oData_Passenger->BookingTourPassenger_Status == 2 && $oData_Passenger->User_Type != 2) {
            try {
                if (!config('var.TESTMODE_AUTOREVIEWMAIL')) {
                    Mail::to($oData_Passenger->Passenger_Email)->send($oMail_User);
                } else {
                    Mail::to(config('var.SEND_EMAIL_ACCESSDATA'))->send($oMail_User);
                }
            } catch (Throwable $t) {
            }
            return true;
        }
        return false;
    }

    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();
            $oParam = array($Id);
            $oData  = DB::select('call sp_group_delete(?)', $oParam);

            //  RESPONSE
            if ($oData[0]->Response_Success == 1) {
                $this->history->delete(
                    $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);
            $oData = array_map(
                function ($oGroup) {

                    if ($oGroup->Group_ServiceType > 2) {
                        $oGroup->Fligth = GroupReports::cutFlyes($oGroup->Service_Detail);
                        if ($oGroup->Group_ServiceType > 3) {
                            $oGroup->BookingTourPassenger_Hotel = $oGroup->Fligth[2];
                        } else {
                            $oGroup->BookingTourPassenger_Hotel = $oGroup->Fligth[1];
                        }
                    } else {
                        $oGroup->Fligth = [];
                    }
                    return $oGroup;
                },
                DB::select('call sp_group_index(?)', $oParam)
            );

            $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, $Type)
    {
        $oResponse  = array();
        $oValParams = array(
            'DateStart' => 'required|string',
            'DateEnd'   => 'required|string'
        );

        $oResponse = ParamsValidator::Validate_Action($Type, $this->oDomain);

        if ($oResponse["Response_Code"] == 200) {
            // VALIDANDO DATOS
            $oResponse = ParamsValidator::Validate_Request($Request, $oValParams, $this->oDomain);

            //  INGRESANDO DATOS
            if ($oResponse["Response_Code"] == 200) {
                $oParam = [
                    $Type,
                    $Request->input("DateStart"),
                    $Request->input("DateEnd")
                ];

                $oData  = DB::select('call sp_group_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 = array('Date' => 'required|string');

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

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            $oParam = array($Request->input("Date"));

            $oData  = DB::select('call sp_group_search(?)', $oParam);

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


        return ResponseBuilder::Response($oResponse);
    }

    public function Search_Passenger(Request $Request)
    {
        $oResponse  = array();
        $oValParams = array('Text' => 'required|string');

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

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

            $path = config('var.PATH_PUBLIC') . config('var.USER_COUNTRY_THUMB');
            $publicPath = config('var.PATH_PUBLIC');

            $oParam = [
                $Request->input("Text"),
                1,
                $path,
                $publicPath
            ];

            $oData  = DB::select('call sp_group_passenger_search(?,?,?,?)', $oParam);

            $oParam = [$Request->input("Text"), 2, $path, $publicPath];

            $oData = array_merge($oData, DB::select('call sp_group_passenger_search(?,?,?,?)', $oParam));

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


        return ResponseBuilder::Response($oResponse);
    }

    public function Report(Request $Request)
    {
        $oResponse  = array();
        $oValParams = array('Date' => 'required|string');

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

        if (!$Request->input('DateEnd')) {
            $dateEnd = $Request->input('Date');
        } else {
            $dateEnd = $Request->input('DateEnd');
        }

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            $oParam = array($Request->input("Date"), $dateEnd);

            $oData  = DB::select('call sp_group_report(?,?)', $oParam);

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

        return ResponseBuilder::Response($oResponse);
    }

    public function Report_Paginated(Request $Request)
    {

        (new LaravelValidator)->validate($Request->all(), $this->oDomain, GroupValidators::REPORT_GROUP);
        $listInput = (new LaravelListValidator($Request))->__invoke(LaravelListValidator::FIND, $this->oDomain);

        $response = (new ReportGroupQueryHandler(
            new ReportGroupFinder(new MysqlReportGroupRepository),
            new ReportGroupCounter(new MysqlReportGroupRepository)
        ))->__invoke(
            new ReportGroupQuery(
                $Request->input('Date'),
                $Request->input('DateEnd') ?: $Request->input('Date'),
                $listInput
            )
        );

        $oResponse["Response_Status"]           = 200;
        $oResponse["Response_Code"]             = 200;
        $oResponse["Response_Domain"]           = $this->oDomain;
        $oResponse["Response_Message"]          = $this->oDomain . " report";
        $oResponse["Response_Data"]             = $response['Response_Data'];
        $oResponse["Response_Count"]            = $response['Response_Count'];
        $oResponse["Response_Error_Message"]    = "";
        $oResponse["Response_Error_Reason"]     = "";


        return ResponseBuilder::Response($oResponse);
    }

    public function Slave_Insert_All(Request $Request)
    {
        $oSucces    = true;
        $oResponse  = array();
        $oValParams = array(
            'Id_Master'     => 'required|int',
            'Group'         => 'required|string'
        );


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

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

            $Group = json_decode($Request->input("Group"));

            for ($i = 0; $i < count($Group); $i++) {
                $this->history->obtainOld($Group[$i]->Id_Group);
                $oParam = array(
                    $Group[$i]->Id_Group,
                    $Request->input("Id_Master"),
                    $Request->header("Token")
                );
                $oData = DB::select('call sp_group_slave_insert(?,?,?)', $oParam);

                if ($oData[0]->Response_Success == 0) {
                    $oSucces = false;
                    break;
                }
                $this->queryBus->ask(new UpdateGroupDateUpdateQuery($Group[$i]->Id_Group));
                $this->history->update(
                    $Group[$i]->Id_Group,
                    $this->history->oldValue,
                    [
                        'Id_Master' => $Request->input('Id_Master'),
                    ],
                    $Request
                );
            }

            if ($oSucces == true) {
                $oData = array(
                    array(
                        "Response_Status"   => 200,
                        "Response_Code"     => 200,
                        "Response_Message"  => "Grupos esclavos 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 Slave_Insert(Request $Request)
    {
        $oResponse  = array();
        $oValParams = array(
            'Id_Group'      => 'required|int',
            'Id_Master'     => '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_Group"));

            $oParam = array(
                $Request->input("Id_Group"),
                $Request->input("Id_Master"),
                $Request->header("Token")
            );
            $oData = DB::select('call sp_group_slave_insert(?,?,?)', $oParam);

            //  RESPONSE
            if ($oData[0]->Response_Success == 1) {
                $this->queryBus->ask(new UpdateGroupDateUpdateQuery($Request->input("Id_Group")));
                $this->history->update(
                    $Request->input("Id_Group"),
                    $this->history->oldValue,
                    [
                        'Id_Master' => $Request->input('Id_Master'),
                    ],
                    $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 Slave_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);
            $oParam = array($Id);
            $oData  = DB::select('call sp_group_slave_delete(?)', $oParam);

            //  RESPONSE
            if ($oData[0]->Response_Success == 1) {
                $this->queryBus->ask(new UpdateGroupDateUpdateQuery($Id));
                $this->history->update(
                    $Id,
                    $this->history->oldValue,
                    [
                        'Id_Master' => 0
                    ],
                    $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 Slave_List(Request $Request, $Id)
    {
        $oResponse  = array();
        $oValParams = array();

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

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

            $oData  = (new GroupSlaveList(new MysqlGroupSlaveRepository))(
                new IdGroup($Id),
                new IncludeSelf(IncludeSelf::ANSWER_NO)
            );

            $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 Slave_List_Complete(Request $Request, $Id)
    {
        $oResponse  = array();
        $oValParams = array();

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

        if ($oResponse["Response_Code"] == 200) {
            $oData = (new GroupSlaveList(new MysqlGroupSlaveRepository))(
                new IdGroup($Id),
                new IncludeSelf(IncludeSelf::ANSWER_YES)
            );

            $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 Slave_Search(Request $Request, $Id)
    {
        $oResponse  = array();
        $oValParams = array();

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

        if ($oResponse["Response_Code"] == 200) {
            $oParam = array($Id);
            $oData  = DB::select('call sp_group_slave_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 reportUnitary(Request $Request)
    {
        return ResponseBuilder::response(GroupReports::reportExcelDataIdGroup($Request, $this->oDomain));
    }

    public function Report_Group_Pdf(Request $Request)
    {
        return ResponseBuilder::response(GroupReports::Report_Excel_Group_Data($Request, $this->oDomain));
    }

    public function Report_Excel_Group(Request $Request)
    {
        $oResponse = GroupReports::Report_Excel_Group_Data($Request, $this->oDomain);

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            if ($Request->input("resume") == 0) {
                (new ExcelGroupReport())->exportToExcel($oResponse["Response_Data"], $Request->input("Date"));
            } else {
                (new ExcelGroupResumeReport())->exportToExcel([(object)['Groups' => $oResponse["Response_Data"]]]);
            }
        } else {
            return ResponseBuilder::Response($oResponse);
        }
    }

    public function Report_Group_List_Pdf(Request $Request)
    {
        return ResponseBuilder::response(GroupReports::Report_Excel_Data($Request, $this->oDomain));
    }

    public function Report_Excel(Request $Request)
    {
        $oResponse = GroupReports::Report_Excel_Data($Request, $this->oDomain);

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            if ($Request->input("resume") == 0) {
                (new ExcelGroupReport())->exportToExcel($oResponse["Response_Data"], $Request->input("Date"));
            } else {
                (new ExcelGroupResumeReport())->exportToExcel([(object)['Groups' => $oResponse["Response_Data"]]]);
            }
        } else {
            return ResponseBuilder::Response($oResponse);
        }
    }

    public function Report_Excel_Review(Request $Request, $Id)
    {

        $oResponse = GroupReports::Report_Review_Data($Id, $this->oDomain);

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            (new ExcelGroupReviewsReport())->exportToExcel($oResponse["Response_Data"]);
        } else {
            return ResponseBuilder::Response($oResponse);
        }
    }

    public function Report_Group_Review_Pdf(Request $Request, $Id)
    {
        return ResponseBuilder::Response(GroupReports::Report_Review_Data($Id, $this->oDomain));
    }

    public static function sendPassengerReviewMail($Id_Passenger, $oDomain)
    {
        try {
            $credentials = BookingMailSender::getCredentialList();
            $mails = BookingMailSender::mergeCredentials([], 'Mail_Reviews', $credentials);

            $ResourcesUrl = BookingMailSender::getResourcesUrl()[0]->Credential_Value;

            $oPassenger = GroupReports::Report_Passenger_Review_Data($Id_Passenger, $oDomain);
            $Variables              = array(
                "Lang"          => 1,
                "Passenger"     => $oPassenger,
                'ResourcesUrl'  => $ResourcesUrl
            );

            $oMail_User             = new c_Mail_User;
            $oMail_User->Type       = 5;
            $oMail_User->Subject    = "Passenger Review";
            $oMail_User->Content    = $Variables;

            $credentialMails = [];
            foreach ($mails as $mail) {
                if (filter_var($mail['email'], FILTER_VALIDATE_EMAIL)) {
                    $credentialMails[] = $mail;
                }
            }


            $shipper = new EmailShipShipper(
                new MysqlEmailShipShippedRepository,
                new MysqlEmailShipRepository
            );

            $shipper->__invoke($credentialMails, [], [], $oMail_User);
            // Mail::to($credentialMails)->send($oMail_User);
        } catch (\Throwable $t) {
        }
    }

    public function Selector(Request $Request, $Id)
    {
        if (is_numeric($Id)) {
            return SELF::Index($Request, $Id);
        } else if ($Id == "search") {
            return SELF::Search($Request, $Id);
        } else if ($Id == "report") {
            return SELF::Report($Request, $Id);
        } else {
            return SELF::List($Request, $Id);
        }
    }
}
