<?php


namespace App\Services\MobileMoney\Orange;


use App\Models\PaymentManagement\PaymentMethod;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Psr7\Response;
use Monolog\Handler\RotatingFileHandler;

class OrangeMobileMoney{

    private $token_url ;

    private $api_user_name;
    private $api_password;

    private $api_consumer_key;
    private $api_consumer_secret;
    private $pin;

    private $config;

    /**
     * Orange Money  API Base url
     */
    private $base_url = "https://api.orange.com/";
    /**
     * The Query to run against the FileSystem
     * @var Client;
     */
    private $client ;

    /**
     * @var string or null
     */
    private  $merchant_key;

    /**
     * @var string or null
     */
    private  $return_url;
    /**
     * @var string or null
     */
    private  $cancel_url;
    /**
     * @var string or null
     */
    private  $notif_url;

    private  $access_token;
    private $options  = [];
    public $log_directory_name = "orange-momo";

    public function __construct(PaymentMethod $paymentMethod = null){

        $this->log = new \Monolog\Logger($this->log_directory_name);
        $this->config = (object) config('orange-momo');

        if ($paymentMethod){
            if ($paymentMethod->api_config){
                $this->config = (object) $paymentMethod->api_config;
            }
        }

        $this->base_url  =  $this->config->base_url;
        $this->token_url  =  $this->config->token_url;

        $this->client = new Client([
            'base_uri' => $this->base_url,
            'verify'=> $this->config->verify_ssl ?? true,
        ]);

        $this->merchant_key =  $this->config->merchant_key;
        $this->pin =  $this->config->pin;
        $this->return_url   =  $this->config->return_url;
        $this->cancel_url   =  $this->config->cancel_url;
        $this->notif_url    =  $this->config->notif_url;

        $this->api_consumer_key     =  $this->config->api_consumer_key;
        $this->api_consumer_secret   =  $this->config->api_consumer_secret;

        $this->api_user_name     =  $this->config->api_user_name;
        $this->api_password     =  $this->config->api_password;

        $this->access_token = $this->getAccessToken();

        $this->options = [
            "headers" => [
                'Authorization' => 'Bearer '.$this->access_token,
                'Accept'        =>'application/json',
                'Content-Type'  =>'application/json',
                'User-Agent'  =>'user agent',
            ],
        ];

    }

    /** Retourne le token d'accès utilisateur
     * @return mixed|null
     * @throws GuzzleException
     */
    public function getAccessToken(){
        $data = $this->getToken();
        return $data["access_token"] ?? null;
    }

    /** Retourne une nouvelle reference de transaction
     * @return mixed|null
     * @throws GuzzleException
     */
    public function getPayToken(){
        $this->options['headers']['X-AUTH-TOKEN'] = base64_encode($this->api_user_name.':'.$this->api_password);
        $response = $this->apiCall("post",$this->base_url.'/mp/init',$this->options);
        return $response['data']['payToken'] ?? null;
    }

    /**
     * Create API query and execute a GET/POST request
     * @param string $httpMethod GET/POST
     * @param string $endpoint
     * @param array $options
     * @return mixed|string
     * @throws GuzzleException
     */
    private function apiCall($httpMethod = "post", $endpoint = "", $options = []){
        // POST method or GET method
        try{
            /** @var Response $response */
            $response = $this->client->request(strtoupper($httpMethod),$endpoint,$options);
            return  json_decode($response->getBody()->getContents(),true);
        }catch (Exception $exception){
            write_log("orange-momo",$exception,"error",$endpoint);
          return  $exception->getMessage();
        }
    }

    /** Retourne le Token
     * @return mixed|string
     * @throws GuzzleException
     */
    public function getToken(){
        $options = [
            'headers'=> [
                'Authorization' => 'Basic '.base64_encode($this->api_consumer_key.':'.$this->api_consumer_secret),
                'Accept'        =>'application/json',
                'Content-Type'  =>'application/x-www-form-urlencoded'
            ],
            'form_params' => [
                'grant_type'=>'client_credentials',
            ]
        ];
        return $this->apiCall("post",$this->token_url,$options);
    }


    /** Initie un nouveau paiement
     * @param $datas
     * @return mixed|null
     * @throws GuzzleException
     */
    public function transact($datas){

        $body = [
            "notifUrl" => $this->notif_url,
            "channelUserMsisdn" => $this->merchant_key,
            "amount" => (string) $datas['amount'],
            "subscriberMsisdn" => $datas['phoneNumber'],
            "pin" => $this->pin,
            "orderId" => $datas['order_ref'],
            "description" => $datas['message'] ,
            "payToken" => $datas['pay_token']
        ];

//        $this->options['body'] = json_encode($body);
        $this->options['json'] = $body;

        $result = $this->apiCall("post",$this->base_url.'/mp/pay',$this->options);

        return $result['data'] ?? null;
    }

    /** Retourne le status de la transaction
     * @param string $payToken La reference de la transaction
     * @return mixed|null
     * @throws GuzzleException
     */
    public function getTransactStatus($payToken){
        $response =  $this->apiCall('get',$this->base_url.'/mp/paymentstatus/'.$payToken, $this->options);
        return $response['data'] ?? null;
    }
}

