<?php

namespace App\Core\Payment\RetailPay;

use App\Exceptions\ApiErrorException;
use App\Exceptions\ApplicationError;
use Auth;
use Carbon\Carbon;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ServerException;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Log;
use Exception;

class RetailPay
{

    private $requestUrl;

    public function __construct($paymentInitializeParam)
    {
        $this->restClient = new Client();

        $this->requestUrl = 'https://api.sprynto-psp.com';
        if ($paymentInitializeParam['env'] == 'test') {
            $this->requestUrl = 'https://api.sprynto-psp-test.com';
        }


        $this->userName = $paymentInitializeParam['userName'];
        $this->password = $paymentInitializeParam['password'];
        $this->ipAddress = isset($paymentInitializeParam['ipAddress']) ? $paymentInitializeParam['ipAddress'] : '185.137.215.118';

    }

    private function makeRequest($type, $method, $payloadData = [])
    {

        $response = ['status' => false, 'message' => ''];

        try {

            $requestParams['headers']['Authorization'] = 'Basic ' . base64_encode($this->userName . ':' . $this->password);
            $requestParams['headers']['Content-Type'] = 'application/json';

            if (!empty($payloadData)) {
                $requestParams['body'] = json_encode($payloadData);
            }

            $result = $this->restClient->request($type, $this->requestUrl . '/' . $method, $requestParams);

            $getResponseBody = $result->getBody()->getContents();
            $getResponseData = $getResponseBody ? json_decode($getResponseBody, 1) : [];

            if ($getResponseData) {
                $response = [
                    'status' => true,
                    'serviceResponse' => $getResponseData
                ];
            }

        } catch (RequestException  $e) {

            $message = null;
            if ($e->hasResponse()) {
                $responseError = $e->getResponse();
                $responseErrorBody = $responseError->getBody()->getContents();
                $responseErrorArray = json_decode($responseErrorBody, true);
                if (isset($responseErrorArray['failure_message'])) {
                    $message = $responseErrorArray['failure_message'];
                }
            } else {
                $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            }

            $response['message'] = $message;
            Log::debug($message);

        } catch (ClientException | ServerException | Exception  $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            $response['message'] = $message;
            Log::debug($message);

        }

        if (!$response['status']) {
            Log::error($method);
            Log::error($payloadData);
            Log::error($response);
        }

        return $response;

    }

    public function ordersAuthorize($param)
    {

        $response = ['status' => false, 'message' => ''];
        try {

            $param['creditCard']['installment'] = $param['creditCard']['installment'] == 0 ? 1 : $param['creditCard']['installment'];

            $method = 'orders/authorize';
            $payloadData = [
                'amount' => $param['amount'],
                'pan' => $param['creditCard']['number'],
                'card' => [
                    'cvv' => $param['creditCard']['cvv'],
                    'holder' => $param['creditCard']['holderName'],
                    'expiration_month' => $param['creditCard']['expiryMonth'],
                    'expiration_year' => $param['creditCard']['expiryYear'],
                ],
                'client' => [
                    'name' => $param['client']['name'],
                    'email' => $param['client']['email'],
                    'phone' => $param['client']['phone'],
                ],
                'location' => [
                    'ip' => $this->ipAddress
                ],
                'currency' => $param['currencyCode'],
                'merchant_order_id' => $param['orderId'],
                'description' => 'Order Code: ' . $param['orderCode'],
                'options' => [
                    'force3d' => 1,
                    'return_url' => $param['paymentCheckUrl'],
                    'secure3d20_return_url' => $param['paymentCheckUrl'],
                ]

            ];


            \Illuminate\Support\Facades\Log::debug(json_encode($payloadData));

            $checkRequest = $this->makeRequest('POST', $method, $payloadData);

            //dd($checkRequest);

            if (!$checkRequest['status']) {
                throw new ApiErrorException($checkRequest['message']);
            }

            $serviceResponse = $checkRequest['serviceResponse'];
            $serviceResponseOrder = reset($serviceResponse['orders']);

            $response = [
                'status' => true,
                'data' => $serviceResponseOrder
            ];


        } catch (ApiErrorException $e) {
            $response = ['status' => false, 'message' => $e->getMessage()];
        } catch (Exception $e) {
            $response = ['status' => false, 'message' => $e->getMessage()];
            Log::error($response);
        }

        return $response;

    }

    public function orderCharge($orderId)
    {

        $response = ['status' => false, 'message' => ''];
        try {

            $method = 'orders/' . $orderId . '/charge';
            $orderCharge = $this->makeRequest('POST', $method);

            if (!$orderCharge['status']) {
                throw new ApiErrorException($orderCharge['message']);
            }


            $serviceResponse = $orderCharge['serviceResponse'];
            $serviceResponseOrder = reset($serviceResponse['orders']);


            if ($serviceResponseOrder['status'] != 'charged') {
                if (isset($serviceResponseOrder['failure_message'])) {
                    throw new ApiErrorException($serviceResponseOrder['failure_message']);
                } else {
                    throw new ApiErrorException('authorized, but not charged');
                }

            }

            $response = [
                'status' => true,
                'data' => $serviceResponseOrder
            ];

        } catch (ApiErrorException $e) {
            $response = ['status' => false, 'message' => $e->getMessage()];
        } catch (Exception $e) {
            $response = ['status' => false, 'message' => $e->getMessage()];
            Log::error($response);
        }

        if (isset($checkStatusRequest['serviceResponse'])) {
            $response['serviceResponse'] = $checkStatusRequest['serviceResponse'];
        }

        return $response;

    }

    public function checkPaymentStatus($orderId)
    {

        $response = ['status' => false, 'message' => ''];
        try {

            $method = 'orders/' . $orderId;
            $checkStatusRequest = $this->makeRequest('GET', $method);

            if (!$checkStatusRequest['status']) {
                throw new ApiErrorException($checkStatusRequest['message']);
            }

            $serviceResponse = $checkStatusRequest['serviceResponse'];
            $serviceResponseOrder = reset($serviceResponse['orders']);


            if ($serviceResponseOrder['status'] != 'charged') {
                if (isset($serviceResponseOrder['failure_message'])) {
                    throw new ApiErrorException($serviceResponseOrder['failure_message']);
                } else {
                    throw new ApiErrorException('authorized, but not charged');
                }

            }

            $response = [
                'status' => true,
                'data' => $serviceResponseOrder
            ];

        } catch (ApiErrorException $e) {
            $response = ['status' => false, 'message' => $e->getMessage()];
        } catch (Exception $e) {
            $response = ['status' => false, 'message' => $e->getMessage()];
            Log::error($response);
        }

        if (isset($checkStatusRequest['serviceResponse'])) {
            $response['serviceResponse'] = $checkStatusRequest['serviceResponse'];
        }

        return $response;

    }

}
