<?php

namespace App\Http\Controllers\Client;

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\Modules\Credential\Domain\CredentialList;
use App\Modules\Niubiz\Domain\NiubizMdd;
use App\Modules\Shared\Domain\ValueObject\DateValueObject;
use App\Providers\BookingMailSender;
use Illuminate\Support\Facades\DB;

class c_Cash_Movement_Temp extends Controller
{
    private $oDomain;

    public function __construct(
        private PassengerUpdater $passengerUpdater,
    ) {
        $this->oDomain = "Cash Movement Temp";
    }

    public function Index($Id)
    {
        $oResponse = ParamsValidator::Validate_Id($Id, $this->oDomain);

        if ($oResponse["Response_Code"] == 200) {
            $oData  = DB::select('call sp_client_niubiz_purchase_index(?)', [$Id]);

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

        $oResponse = ParamsValidator::Validate_Request(
            $request,
            [
                'CashMovementTemp_Amount'           => 'required|numeric',
                'CashMovementTemp_Currency'         => 'required|string|max:4',
                'CashMovementTemp_Name'             => 'required|string|max:100',
                'CashMovementTemp_LastName'         => 'required|string|max:100',
                'CashMovementTemp_Email'            => 'required|string|max:250',
                'CashMovementTemp_Country'          => 'required|string|max:100',
                'CashMovementTemp_City'             => 'required|string|max:100',
                'CashMovementTemp_Address'          => 'required|string|max:250',
                'CashMovementTemp_Phone'            => 'required|string|max:50',
                'CashMovementTemp_ReceiptNumber'    => 'required|string|max:100',
                'CashMovementTemp_CardLast'         => 'required|string|max:10',
                'CashMovementTemp_CardNumber'       => 'required|string|max:20',
                'CashMovementTemp_CardBrand'        => 'required|string|max:50',
                'CashMovementTemp_CardType'         => 'required|string|max:50',
                'CashMovementTemp_CardIssuer'       => 'required|string|max:50',
                'CashMovementTemp_Remark'           => 'string',
                'CashMovementTemp_Invoices'         => 'required|string',
                'Id_TypePayment'                    => 'int',
                'Id_Schedule'                       => 'int'
            ],
            $this->oDomain
        );

        if ($oResponse['Response_Code'] != 200) {
            return ResponseBuilder::Response($oResponse);
        }

        $credentials = BookingMailSender::getCredentialList();
        $auth = BookingMailSender::filterCredential($credentials, 'Niubiz_Auth')[0];
        $merchantId = BookingMailSender::filterCredential($credentials, 'Niubiz_MerchantId')[0];

        $niubiz = new c_Niubiz();
        $res = $niubiz->getAccessToken($auth->Credential_Value);

        if (!$res['success']) {
            return $niubiz->returnException($res['code'], 'Niubiz Access Response: ' . $res['body']);
        }
        $accessToken = $res['body'];


        $res = $niubiz->createSessionToken(
            $accessToken,
            $request->input('CashMovementTemp_Amount'),
            $request->ip(),
            $merchantId->Credential_Value,
            new NiubizMdd($request->input('CashMovementTemp_Email'))
        );

        if (!$res['success']) {
            return $niubiz->returnException($res['code'], 'Niubiz Session Response: ' . $res['body']);
        }

        $oParam = [
            $request->input('CashMovementTemp_Amount'),
            $request->input('CashMovementTemp_Currency'),
            $request->input('CashMovementTemp_Name'),
            $request->input('CashMovementTemp_LastName'),
            $request->input('CashMovementTemp_Email'),
            $request->input('CashMovementTemp_Country'),
            $request->input('CashMovementTemp_City'),
            $request->input('CashMovementTemp_Address'),
            $request->input('CashMovementTemp_Phone'),
            $request->input('CashMovementTemp_ReceiptNumber'),
            $request->input('CashMovementTemp_CardLast'),
            $request->input('CashMovementTemp_CardNumber'),
            $request->input('CashMovementTemp_CardBrand'),
            $request->input('CashMovementTemp_CardType'),
            $request->input('CashMovementTemp_CardIssuer'),
            $request->input('CashMovementTemp_Remark'),
            $request->input('CashMovementTemp_Invoices'),
            2,
            $accessToken,
            $request->input('Id_TypePayment'),
            $request->input('Id_Schedule'),
        ];

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

        $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"]             = [
            'Niubiz_AccessToken' => $accessToken,
            'Niubiz_SessionToken' => $res['body'],
            'Niubiz_MerchantId' => $merchantId,
            'Niubiz_Number' => $oData[0]->Response_Id,
            'Id_CashMovementTemp' => $oData[0]->Response_Id
        ];
        $oResponse["Response_Error_Message"]    = $oData[0]->Response_Message;
        $oResponse["Response_Error_Reason"]     = $oData[0]->Response_Reason;

        return ResponseBuilder::Response($oResponse);
    }

    private function updateCashMovementTemp($id, $message, $responseData, $status)
    {
        return DB::select('CALL sp_client_niubiz_purchase_update(?,?,?,?)', [$id, $message, $responseData, $status]);
    }

    private function captureWebUrl(Request $request, CredentialList $list)
    {
        $web = $list->getValue('Internal_Web_URL');
        if ($request->input('useWeb', '')) {
            $web = $list->getValue('Web_URL');
        }
        return $web . $request->input('redirectTo');
    }

    public function ValidateCashMovement(Request $Request, $Id)
    {
        $credentials = BookingMailSender::getCredentialList();
        $credentialList = new CredentialList($credentials);
        $merchantId = BookingMailSender::filterCredential($credentials, 'Niubiz_MerchantId')[0];
        $webUrl = $this->captureWebUrl($Request, $credentialList);

        $oResponse  = array();
        $oResponse = ParamsValidator::Validate_Request(
            $Request,
            [
                'transactionToken'  => 'required|string',
                'redirectTo'        => 'string',
                'useWeb'            => 'string'
            ],
            $this->oDomain
        );

        if ($oResponse['Response_Code'] != 200) {
            $this->updateCashMovementTemp($Id, $oResponse['Response_Message'], '', 1);
            return redirect()->to($webUrl . '?errorId=' . $Id);
        }
        $oData = DB::select('CALL sp_client_niubiz_purchase_index(?)', [$Id]);

        if (!count($oData)) {
            $this->updateCashMovementTemp($Id, 'The cash movement temp doesn\'t exists', '', 1);
            return redirect()->to($webUrl . '?errorId=' . $Id);
        }

        $niubiz = new c_Niubiz();

        $res = $niubiz->getTransactionAuthorization(
            $oData[0]->CashMovementTemp_AccessToken,
            $Request->input('transactionToken'),
            $oData[0]->Id_NiubizPurchase,
            $oData[0]->CashMovementTemp_Amount,
            $merchantId->Credential_Value
        );

        if (!$res['success']) {
            if (is_string($res['body'])) {
                $this->updateCashMovementTemp($Id, $res['body'], '', 1);
                return redirect()->to($webUrl . '?errorId=' . $Id);
            } else {
                $message = isset($res['body']->data->ACTION_DESCRIPTION)
                    ? $res['body']->data->ACTION_DESCRIPTION
                    : $res['body']->errorMessage;
                $this->updateCashMovementTemp($Id, $message, json_encode($res['body']), 1);
                return redirect()->to($webUrl . '?errorId=' . $Id);
            }
        }

        $data = $res['body'];
        $this->updateCashMovementTemp($Id, '', json_encode($data), 2);

        $request = new Request([
            'CashMovement' => json_encode([
                'CashMovement_Amount' => $data->order->amount,
                'CashMovement_Currency' => $data->order->currency,
                'CashMovement_Name' => '-',
                'CashMovement_LastName' => '-',
                'CashMovement_Email' => '-',
                'CashMovement_Country' => '-',
                'CashMovement_City' => '-',
                'CashMovement_Address' => '-',
                'CashMovement_Phone' => '-',
                'CashMovement_ReceiptNumber' => $data->order->purchaseNumber,
                'CashMovement_CardLast' => '-',
                'CashMovement_CardNumber' => $data->dataMap->CARD,
                'CashMovement_CardBrand' => $data->dataMap->BRAND,
                'CashMovement_CardType' => '-',
                'CashMovement_CardIssuer' => '-',
                'Invoices' => $oData[0]->CashMovementTemp_Invoices,
            ]),
            'Id_Schedule' => $oData[0]->Id_Schedule
        ]);
        return $this->InsertCashMovement(
            $request,
            $webUrl,
            $Id,
            $data
        );
    }

    public function InsertCashMovement(Request $Request, $webUrl, $Id_CashMovementTemp, $data)
    {

        $oResponse = ParamsValidator::Validate_Request($Request, [
            'Id_Schedule'           => 'required|int',
            'CashMovement'          => 'required|string'
        ], $this->oDomain);

        if ($oResponse["Response_Code"] == 200) {
            $oCashMovement  = json_decode($Request->input('CashMovement'));

            $oParam = [
                DateValueObject::reducedNowToPeru(),
                $oCashMovement->CashMovement_Amount,
                $oCashMovement->CashMovement_Currency,
                $oCashMovement->CashMovement_Name,
                $oCashMovement->CashMovement_LastName,
                $oCashMovement->CashMovement_Email,
                $oCashMovement->CashMovement_Country,
                $oCashMovement->CashMovement_City,
                $oCashMovement->CashMovement_Address,
                $oCashMovement->CashMovement_Phone,
                $oCashMovement->CashMovement_ReceiptNumber,
                $oCashMovement->CashMovement_CardLast,
                $oCashMovement->CashMovement_CardNumber,
                $oCashMovement->CashMovement_CardBrand,
                $oCashMovement->CashMovement_CardType,
                $oCashMovement->CashMovement_CardIssuer,
                '',
                2
            ];

            $oDataCashMovement = DB::select('call sp_cash_movement_insert(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,0)', $oParam);
            $oData = $oDataCashMovement;



            if ($oData[0]->Response_Success == 1) {
                $Id_CashMovement = $oData[0]->Id_CashMovement;
                if ($Request->input('Id_Schedule') != 0) {
                    #region Schedule Detail
                    $oInvoice = json_decode($oCashMovement->Invoices);

                    foreach ($oInvoice as $detail) {
                        $oData = DB::select('call sp_cash_movement_detail_insert(?,?,?,?,?)', [
                            $detail->Amount,
                            $oDataCashMovement[0]->Id_CashMovement,
                            $detail->Id_Invoice,
                            1,
                            1
                        ]);
                        if ($oData[0]->Response_Success != 1) {
                            break;
                        } else {
                            $invoice = DB::select('call sp_invoice_get(?)', [$detail->Id_Invoice])[0];
                            $this->passengerUpdater->updateLockHtlCampBookingPassenger($invoice->Id_Passenger);
                        }
                    }
                    #endregion

                    #region Schedule
                    if ($oData[0]->Response_Success == 1) {
                        $scheduleData = DB::select('call sp_schedule_pay(?)', [$Request->input("Id_Schedule")]);

                        if ($scheduleData[0]->Response_Success == 1) {
                            try {
                                $oSchedule = DB::select(
                                    'call sp_schedule_index(?)',
                                    [$Request->input("Id_Schedule")]
                                );
                                BookingMailSender::sendBookingByMail(
                                    $oSchedule[0]->Id_Booking,
                                    $this->oDomain,
                                    BookingMailSender::ONLY_PAYMENT
                                );
                            } catch (\Throwable $ex) {
                            }
                        }
                    }

                    #endregion
                } else {
                    $oSuccess = true;
                    $oInvoice = json_decode($oCashMovement->Invoices);

                    foreach ($oInvoice as $detail) {

                        $oData = DB::select('call sp_cash_movement_detail_insert(?,?,?,?,?)', [
                            $detail->Amount,
                            $oData[0]->Id_CashMovement,
                            $detail->Id_Invoice,
                            1,
                            1
                        ]);
                        if ($oData[0]->Response_Success == 0) {
                            $oSuccess = false;
                            break;
                        }
                    }

                    if ($oSuccess == true) {
                        $oData = [[
                            "Response_Status"   => 200,
                            "Response_Code"     => 200,
                            "Response_Message"  => "Pasajeros guardados con éxito",
                            "Response_Reason"   => null
                        ]];

                        $oData = json_decode(json_encode($oData));
                    }
                }
            }

            #region Get data

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

            #endregion
        }

        if ($oResponse["Response_Status"] == 200) {
            return redirect()->to($webUrl . '?paymentId=' . $Id_CashMovement);
        } else {
            $this->updateCashMovementTemp($Id_CashMovementTemp, $oResponse["Response_Error_Reason"], json_decode($data), 2);
            return redirect()->to($webUrl . '?errorId=' . $Id_CashMovementTemp);
        }
    }
}
