<?php


namespace App\Services\Xpeedy;


use Exception;
use GuzzleHttp\Client;
use Spatie\Valuestore\Valuestore;

class Xpeedy {

    protected $client;
    protected $config;
    protected $store;

    public function __construct(array $config = null , array $headers = [],Client $client = null){

        if (empty($config)){
            $config = config('xpeedy');
        }

        throw_if(blank($config) , new Exception(__("Unable to init a Xpeedy-Object Class")));

        $this->setConfigurations($config);

        // Guzzle http request headers.
        $headers = array_merge([
            'Accept' => 'application/json',
            'Content-Type' => 'application/json',
            'x-api-id' => $this->api_id,
        ], $headers);


        if (blank($client)){
            // Set http client.
            $this->client = new Client( [
                                // 'handler' => $handlerStack,
                                'base_uri' => $this->getUrl(),
                                'headers' => $headers,
                                'verify' => $this->config['verify_ssl'] ?? false ,
                            ]);
        }

        $this->store= Valuestore::make(storage_path('app/xpeedy.auth.json'));

        $this->authenticate($this->api_key, $this->api_secret);

    }

    protected function getUrl(){
        return $this->host.$this->base_uri;
    }

    private function setConfigurations($config){
        $config = $this->config;
        $this->base_uri = $config['base_uri'];
        $this->environment = $config['env'];
        $this->log_dir = $config['log_dir'];
    }

    public function request($endpoint, $data , $options = []){
       // $headers =  $options['headers'] ?? null;
        $method =  $options['method'] ?? "get";
        $method = strtolower($method);
        $body = "query";

        if (in_array($method,['post',"put","delete"])){
            $body = "form_params";
        }

        unset($options['method'],$options['data']);

        $options[$body] = $data;

        try {
            $response            =  $this->client->request($method,$endpoint,$options);
            $status              = $response->getStatusCode();
            $response            = json_decode($response->getBody(), true);
            $response['status']  =  $status;

//            throw_if(
//                ($status != 200) ,
//                new Exception('Request to pay transaction - unsuccessful.', 0, null)
//            );

            return $response;

        }catch (Exception $ex) {
            write_log($this->log_dir,$ex);
            throw new Exception('Request to pay transaction - unsuccessful.', 0, $ex);
        }
    }


    private function getAccessToken(){
        $token = $this->store->get("access_token");
        $expired_at = $this->store->get("expired_at");
        $expired = true;

        if (filled($expired_at)) $expired = date_is_expired($expired_at);

        if (blank($token) or $expired){
            $response = $this->authenticate($this->api_key, $this->api_secret);
           // $code = $response['code'] ?? null; // "AUTH_REQUIRED"

            if (isset($response['access_token'])) {
                $this->store->put($response);
                return $this->getAccessToken();
            }
        }
        return $token;
    }


    /** Permet d'inialiser une nouvelle transaction
     * @param array|object $inputs
     * @return mixed
     * @throws Exception
     */
    public function getBriefcase(){
        $tries = 0;
        $max_tries = 3;
        $token  = $this->getAccessToken();

        $options = [
            "headers" => [
                'Authorization' => "Bearer $token",
            ],
        ];
        $response = $this->request("/briefcase/show",$options);

        $tries++;

        $code = $response['code'] ?? null;

        if ($code == "AUTH_REQUIRED"){
            if ($tries != $max_tries){
                $this->authenticate($this->api_key, $this->api_secret);
                return $this->getBriefcase();
            }

        }
        if (isset($response['code'])){

        }
    }


    /**
     * @param string $api_key
     * @param string $api_secret
     * @return mixed
     * @throws Exception
     */
    public function authenticate($api_key , $api_secret){
        $options = [
            "method" => "post",
            "data" => [
                'api_key' => $api_key,
                'api_secret' => $api_secret,
            ],
            "headers" => [
               // 'x-callback-url' => $this->client_callback_url,
            ],
        ];
        return $this->request("/authenticate",$options);
    }


    /** Permet d'inialiser une nouvelle transaction
     * @param array|object $inputs
     * @return mixed
     * @throws Exception
     */
    public function initTransaction($inputs){
        $token  = $this->getAccessToken();

        $options = [
            "method" => "post",
            "data" => [
                'provider' => $inputs['method'],
                'payer_number' => $inputs['payer_number'],
                'amount' => $inputs['amount'],
                'details' => $inputs['details'],
            ],
            "headers" => [
                'Authorization' => "Bearer $token",
            ],
        ];

        return $this->request("/transaction/init",$options);
    }

    public function checkTransaction($transactionId){
        $token  = $this->getAccessToken();
        $options = [
            "headers" => [
                'Authorization' => "Bearer $token",
            ],
        ];
        return $this->request("/transaction/$transactionId/ckeck",$options);
    }
}
