<?php

namespace Mtc\Modules\MtcUnio\Classes;

use Mtc\Modules\MtcUnio\Interfaces\UnioApiRequestable;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;


class UnioApi
{

    const ENDPOINT_CUSTOMER = 'customer';
    const ENDPOINT_ORDER = 'order';
    const ENDPOINT_LEAD = 'lead';

    const ENDPOINT_CUSTOMER_GET = 'customer_get';
    const ENDPOINT_ORDER_GET = 'order_get';

    const ENDPOINT_MESSAGE_SEND = 'message_send';
    const ENDPOINT_UPLOAD_EXEMPTION = 'upload_exemption';


    private static $endpoint_urls = [
        self::ENDPOINT_CUSTOMER => '/customer/upsert',
        self::ENDPOINT_ORDER => '/order/create',
        self::ENDPOINT_LEAD => '/lead/create',

        self::ENDPOINT_CUSTOMER_GET => '/customer',
        self::ENDPOINT_ORDER_GET => '/order',

        self::ENDPOINT_MESSAGE_SEND => '/message/send',
        self::ENDPOINT_UPLOAD_EXEMPTION => '/customer/upload-exemption',
    ];

    private static $instance = null;

    private function __construct() {}


    private function getAccessToken($use_fresh_token = false)
    {
        if ($use_fresh_token) {
            $this->refreshAccessToken();
        }

        return Cache::get('unio_access_token');
    }


    public static function init()
    {
        if (! self::$instance) {
            self::$instance = new self();
        }

        return self::$instance;
    }


    private function refreshAccessToken()
    {
        $access_token = null;

        $ch = curl_init();

        $username = '6e83munisbb77n5bdh26n0jjrk';
        $password = '1pa3vdunbpen9qv54jppvvnack13oceulal5r9am0sq642op40cr';

        curl_setopt($ch, CURLOPT_URL, "https://vyne.auth.eu-west-2.amazoncognito.com/oauth2/token?grant_type=client_credentials");
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/x-www-form-urlencoded',
        ]);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if ($response === false) {
            $error_message = "Request failed.";
        } else if ($http_code != 200) {
            $error_message = "HTTP reponse code: {$http_code}.";
        } else {
            $response = json_decode($response);
            $access_token = $response->access_token;
        }

        if (isset($error_message)) {
            throw new \Exception($error_message . ' ' . curl_error($ch));
        }

        curl_close($ch);

        Cache::put('unio_access_token', $access_token, 60);
    }


    private function getPayload(array $payload_data) : string
    {
        return json_encode($payload_data);
    }


    private function getRequestUrl(string $endpoint_name) : string
    {
        $url = 'https://v7t3jglxhe.execute-api.eu-west-2.amazonaws.com/dev';
        $url .= self::$endpoint_urls[$endpoint_name];

        return $url;
    }


    public function makeRequest(UnioApiRequestable $obj, $use_fresh_token = false) : string
    {
        $response = null;

        $payload = $this->getPayload($obj->getPayloadData());
        $request_url = $this->getRequestUrl($obj->getEndpointName());
        if ($query_string = http_build_query($obj->getQueryParams())) {
            $request_url .= "?{$query_string}";
        }
        $access_token = $this->getAccessToken($use_fresh_token);

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $request_url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            "Authorization: Bearer {$access_token}",
            "x-api-key: IjZRXdnE5w7LlfDqc0adXah6myn8JhF21KFkVzHK",
            "Content-Type: application/json",
        ]);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $obj->getMethodName());
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);

        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if ($response === false) {
            $error_message = "Request failed.";

        } else if (! $use_fresh_token && $http_code == 401) {
            return $this->makeRequest($obj, true);

        } else if ($http_code != 200) {
            $error_message = "HTTP reponse code: {$http_code} | $response";
        }

        if (isset($error_message)) {
            throw new \Exception($error_message . ' ' . curl_error($ch));
        }

        curl_close($ch);

        return $response;
    }

}
