<?php

namespace App\Http\Controllers\Owner;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Http\Helpers\ResponseBuilder;
use App\Http\Helpers\ParamsValidator;
use App\Http\History\HistoryData;
use App\Http\History\HistoryTables;
use App\Modules\Image\Domain\ImageThumbnailData;
use App\Modules\Image\Infraestructure\BasicConfigImageStorage;
use App\Modules\Provider\Application\Index\ProviderIndexerQuery;
use App\Modules\Provider\Application\Index\ProviderIndexerResponse;
use App\Modules\Provider\Infrastructure\ProviderValidators;
use App\Modules\ProviderTypeProvider\Application\Create\ProviderTypeProviderInserterQuery;
use App\Modules\ProviderTypeProvider\Domain\ProviderTypeProviderStatus;
use App\Modules\Shared\Domain\Bus\Query\QueryBus;
use App\Modules\Shared\Validator\Infraestructure\LaravelValidator;
use App\Providers\ExcelProviderServiceReport\ExcelProviderServiceReport;
use App\Providers\ExcelProviderServiceReport\ProviderServiceGroupDto;
use Illuminate\Support\Facades\DB;

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

    public function __construct(
        private QueryBus $queryBus
    ) {
        $this->oDomain = "Provider";
        $this->history = new HistoryData(HistoryTables::provider);
        $this->historyProviderTypeProvider = new HistoryData(HistoryTables::PROVIDER_TYPE_PROVIDER);
    }

    public function Insert(Request $Request)
    {
        (new LaravelValidator())->validate($Request->all(), $this->oDomain, ProviderValidators::insert());

        $thumbnail = new ImageThumbnailData(
            config("var.THUMB_W"),
            config("var.THUMB_H")
        );

        $image = (new BasicConfigImageStorage($Request))->storeImage('provider' . DIRECTORY_SEPARATOR . 'profile', 'Provider_ImgProfile', $thumbnail);

        //  INGRESANDO DATOS
        $oParam = [
            Str::title($Request->input("Provider_BusinessName")),
            Str::title($Request->input("Provider_TradeName")),
            Str::title($Request->input("Provider_NickName")),
            $Request->input("Provider_NoDocument"),
            Str::title($Request->input("Provider_Address")),
            $Request->input("Provider_Phone"),
            isset($image) ? $image->getUrl() : '',
            isset($image) ? $image->getThumbnail() : '',
            $Request->input("Provider_Status"),
            $Request->input("Id_TypeDocument"),
            $Request->input("Id_TypeProvider"),
            $Request->input("Id_Country"),
            $Request->input("Id_State"),
            $Request->input("Id_City")
        ];
        $oData = DB::select('call sp_provider_insert(?,?,?,?,?,?,?,?,?,?,?,?,?,?)', $oParam);

        //  RESPONSE
        if ($oData[0]->Response_Success == 1) {
            $this->history->insertBasic($Request);

            /** @var ProviderTypeProviderInserterResponse $response */
            $response = $this->queryBus->ask(
                new ProviderTypeProviderInserterQuery(
                    ProviderTypeProviderStatus::ACTIVE,
                    $oData[0]->Response_Id,
                    $Request->input('Id_TypeProvider')
                )
            );
            $this->historyProviderTypeProvider->insertBasic($Request, $response->response()['Response_Data']['Id']);
        } else {
        }

        $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 Update(Request $Request)
    {
        (new LaravelValidator())->validate($Request->all(), $this->oDomain, ProviderValidators::update());

        //  INGRESANDO DATOS
        $this->history->obtainOld($Request->input('Id_Provider'));

        $thumbnail = new ImageThumbnailData(
            config("var.THUMB_W"),
            config("var.THUMB_H")
        );

        $image = (new BasicConfigImageStorage($Request))->storeImage('provider' . DIRECTORY_SEPARATOR . 'profile', 'Provider_ImgProfile', $thumbnail);

        /** @var ProviderIndexerResponse $indexResponse */
        $indexResponse = $this->queryBus->ask(new ProviderIndexerQuery($Request->input("Id_Provider")));
        $imgProfile = $this->indexOrEmpty($indexResponse, 'Provider_ImgProfile');
        $imgProfileThumb = $this->indexOrEmpty($indexResponse, 'Provider_ImgProfile_Thumb');

        $oParam = [
            $Request->input("Id_Provider"),
            Str::title($Request->input("Provider_BusinessName")),
            Str::title($Request->input("Provider_TradeName")),
            Str::title($Request->input("Provider_NickName")),
            $Request->input("Provider_NoDocument"),
            Str::title($Request->input("Provider_Address")),
            $Request->input("Provider_Phone"),
            isset($image) ? $image->getUrl() : $imgProfile,
            isset($image) ? $image->getThumbnail() : $imgProfileThumb,
            $Request->input("Provider_Status"),
            $Request->input("Id_TypeDocument"),
            $Request->input("Id_TypeProvider"),
            $Request->input("Id_Country"),
            $Request->input("Id_State"),
            $Request->input("Id_City")
        ];
        $oData = DB::select('call sp_provider_update(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', $oParam);

        //  RESPONSE
        if ($oData[0]->Response_Success == 1) {
            $this->history->updateBasic($Request->input("Id_Provider"), $Request);
        } else {
        }
        $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);
    }

    private function indexOrEmpty(ProviderIndexerResponse $response, $key)
    {
        if (count($response->response())) {
            return $response->response()[0]->{$key};
        } else {
            return '';
        }
    }

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

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

            //  RESPONSE
            if ($oData[0]->Response_Success == 1) {
                $this->history->deleteBasic($Id, $Request);
            } else {
            }

            $oResponse["Response_Status"]           = $oData[0]->Response_Status;
            $oResponse["Response_Code"]             = $oData[0]->Response_Code;
            $oResponse["Response_Domain"]           = $this->oDomain;
            $oResponse["Response_Message"]          = $oData[0]->Response_Message;
            $oResponse["Response_Data"]             = null;
            $oResponse["Response_Error_Message"]    = $oData[0]->Response_Message;
            $oResponse["Response_Error_Reason"]     = $oData[0]->Response_Reason;
        }

        return ResponseBuilder::Response($oResponse);
    }

    public static function appendPath($provider)
    {
        if ($provider->Provider_ImgProfile) {
            $provider->Provider_ImgProfile = config('var.PATH_PUBLIC') . $provider->Provider_ImgProfile;
        }
        if ($provider->Provider_ImgProfile_Thumb) {
            $provider->Provider_ImgProfile_Thumb = config('var.PATH_PUBLIC') . $provider->Provider_ImgProfile_Thumb;
        }
        return $provider;
    }

    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  = DB::select('call sp_provider_index(?)', $oParam);
            $oData = array_map(fn ($provider) => self::appendPath($provider), $oData);

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

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

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

            $oValParams = array('Id_TypeProvider' => 'required|numeric',);

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

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

                $oParam =   [
                    $Id,
                    $Request->input("Id_TypeProvider")
                ];
                $oData  = DB::select('call sp_provider_list(?,?)', $oParam);
                $oData = array_map(fn ($provider) => self::appendPath($provider), $oData);

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

        return ResponseBuilder::Response($oResponse);
    }

    public function ListReview(Request $Request)
    {
        $oResponse  = array();
        //return $Request;
        $oValParams = array(
            'Id'                => 'string',
            'Date_Start'        => 'required|string',
            'Date_End'          => 'required|string'
        );

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

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            $oParam = array(
                $Request->input("Id"),
                $Request->input("Date_Start") . ' 00:00:00',
                $Request->input("Date_End") . ' 23:59:59',
                config('var.PATH_PUBLIC') . config('var.USER_COUNTRY_THUMB')
            );
            $oData  = DB::select('call sp_passenger_review_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 ListServices(Request $Request)
    {
        $oResponse  = array();
        $oValParams = [
            'Id_Provider'       => 'required|int',
            'Group_DateStart'   => 'required|string',
            'Group_DateEnd'     => 'required|string'
        ];

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

        if ($oResponse["Response_Code"] == 200) {
            $oParam = [
                $Request->input("Id_Provider"),
                $Request->input("Group_DateStart"),
                $Request->input("Group_DateEnd")
            ];
            $oData = DB::select('call sp_provider_list_services(?,?,?)', $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 ListServicesExcel(Request $Request)
    {
        $oResponse  = array();
        $oValParams = [
            'Id_Provider'       => 'required|int',
            'Group_DateStart'   => 'required|string',
            'Group_DateEnd'     => 'required|string'
        ];

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

        if ($oResponse["Response_Code"] == 200) {
            $oParam = [
                $Request->input("Id_Provider"),
                $Request->input("Group_DateStart"),
                $Request->input("Group_DateEnd")
            ];
            $oData = array_map(
                function ($prov) {
                    $prov->Passenger = DB::select(
                        'CALL sp_provider_group_passenger_list(?)',
                        [
                            $prov->Id_Group
                        ]
                    );

                    return $prov;
                },
                DB::select('call sp_provider_list_services(?,?,?)', $oParam)
            );

            (new ExcelProviderServiceReport())->exportToExcel(
                array_map([ProviderServiceGroupDto::class, 'fromDTO'], $oData)
            );
        } else {
            return ResponseBuilder::Response($oResponse);
        }
    }

    public function Search(Request $Request)
    {
        $oResponse  = [];
        $oValParams = ['Id_Tour' => 'required|int'];

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

        //  INGRESANDO DATOS
        if ($oResponse["Response_Code"] == 200) {
            $oParam = [date('Y-m-d'), $Request->input("Id_Tour")];
            $oData = DB::select('call sp_provider_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 SearchWithSanction(Request $request)
    {
        $response  = [];
        $params = ['Id_Tour' => 'required|int', 'DateStart' => 'required|string|date'];

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

        //  INGRESANDO DATOS
        if ($response["Response_Code"] == 200) {
            $oParam = [$request->input('DateStart'), $request->input("Id_Tour")];
            $oData = DB::select('call sp_provider_search_with_sanctions(?, ?)', $oParam);
            $response["Response_Status"]           = 200;
            $response["Response_Code"]             = 200;
            $response["Response_Domain"]           = $this->oDomain;
            $response["Response_Message"]          = $this->oDomain . " search";
            $response["Response_Data"]             = $oData;
            $response["Response_Error_Message"]    = "";
            $response["Response_Error_Reason"]     = "";
        }

        return ResponseBuilder::Response($response);
    }

    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 {
            return SELF::List($Request, $Id);
        }
    }
}
