<?php

class Melhorenvio extends RestApi
{

    const cryptoKey = 'bWVsaG9yIGVudmlvIGF1dGVudGljYWNhbw==';

    // Criado como aplicativo na conta da Futura
    const urlApiTeste = 'https://sandbox.melhorenvio.com.br';
    const clientIdFuturaTeste = '1943';
    const clientSecretFuturaTeste = 'stVqukJbf91CjZ3fok4oTgCaTzVT9kPWqgmTi9wk';
    const urlCallbackFuturaTeste = 'http://efutura.futurasistemas.com.br/melhorenvios/melhorenviocallback.php';

    const urlApi = 'https://www.melhorenvio.com.br';
    const clientIdFutura = '3536';
    const clientSecretFutura = 'XscvIwehNkE7J6whXjLrfOIWr1Ax3f2qh0hzWaoC';
    const urlCallbackFutura = 'http://efutura.futurasistemas.com.br/melhorenvios/melhorenviocallback.php';

    private $header;

    private $environment;
    private $urlCallback;
    private $appId;
    private $appSecret;

    private $accessToken = null;
    private $refreshToken;
    private $tokenExpire;

    public function __construct($registry)
    {
        $this->registry = $registry;
        $this->load = $registry->get('load');
        $this->config = $registry->get('config');
        $this->db = $registry->get('db');
        $this->log = $registry->get('log');
        $this->session = $registry->get('session');

        $this->setEnvironment();
        $this->setHeader();

        $this->accessToken = trim($this->config->get('melhorenvio_access_token'));
        $this->refreshToken = trim($this->config->get('melhorenvio_refresh_token'));
        $this->tokenExpire = trim($this->config->get('melhorenvio_token_expire'));
    }

    public function __get($name)
    {
        return $this->registry->get($name);
    }

    public function setHeader()
    {
        $this->header = array(
            "Accept: application/json",
            "Content-Type: application/json",
            "User-Agent: Futura E-commerce (suporte@futurasistemas.com.br)",
        );
    }

    public function getHeader()
    {
        return $this->header;
    }

    public function setEnvironment()
    {
        if ($this->config->get('melhorenvio_environment') == Type_Environment::Tp_Production) {
            $this->environment = self::urlApi;
            $this->appId = trim($this->config->get('melhorenvio_client_id'));
            $this->appSecret = trim($this->config->get('melhorenvio_client_secret'));
            $this->urlCallback = self::urlCallbackFutura;
        } else {
            $this->environment = self::urlApiTeste;
            $this->appId = self::clientIdFuturaTeste;
            $this->appSecret = self::clientSecretFuturaTeste;
            $this->urlCallback = self::urlCallbackFuturaTeste;
        }
    }

    public function getEnvironment()
    {
        return $this->environment;
    }

    public function getLoginUrl()
    {
        $encryption = new Encryption(self::cryptoKey);
        $urlCallbackLoja = $encryption->encrypt($this->urlloja->link('', '', 'NONSSL', false) . 'melhorenviocallback');
        $url = $this->getEnvironment() . '/oauth/authorize?client_id=' . $this->appId
            . '&redirect_uri=' . urlencode($this->urlCallback)
            . '&state=' . urlencode($urlCallbackLoja)
            . '&response_type=code&scope=cart-read cart-write companies-read companies-write coupons-read coupons-write notifications-read orders-read products-read products-write purchases-read shipping-calculate shipping-cancel shipping-checkout shipping-companies shipping-generate shipping-preview shipping-print shipping-share shipping-tracking ecommerce-shipping';
//    String com todas as permissoes
//    cart-read cart-write companies-read companies-write coupons-read coupons-write notifications-read orders-read products-read products-write purchases-read shipping-calculate shipping-cancel shipping-checkout shipping-companies shipping-generate shipping-preview shipping-print shipping-share shipping-tracking ecommerce-shipping transactions-read users-read users-write

        return $url;
    }

    public function getRefreshToken($code)
    {
        $url = $this->getEnvironment() . '/oauth/token';

        $param = array(
            "grant_type" => "authorization_code",
            "client_id" => $this->appId,
            "client_secret" => $this->appSecret,
            "redirect_uri" => $this->urlCallback,
            "code" => $code,
        );

        $param = json_encode($param);

        $data = parent::callAPI($url, 'POST', $param, $this->getHeader(), false, $retorno);

        if (is_object($data) && property_exists($data, 'access_token')) {
            $accessToken = $data->access_token;
            $tokenExpire = $data->expires_in;
            $refreshToken = $data->refresh_token;
            $this->setAccess($accessToken, $refreshToken, $tokenExpire);
        }
    }

    public function getAccessToken($refreshToken)
    {
        $url = $this->getEnvironment() . '/oauth/token';

        $param = array(
            "grant_type" => "refresh_token",
            "client_id" => $this->appId,
            "client_secret" => $this->appSecret,
            "refresh_token" => $refreshToken,
        );

        $param = json_encode($param);

        $data = parent::callAPI($url, 'POST', $param, $this->getHeader(), false, $retorno);

        if (is_object($data) && property_exists($data, 'access_token')) {
            $accessToken = $data->access_token;
            $tokenExpire = $data->expires_in;
            $refreshToken = $data->refresh_token;
            $this->setAccess($accessToken, $refreshToken, $tokenExpire);
        }

        return $data;
    }

    public function setAccess($accessToken, $refreshToken, $tokenExpire)
    {
        $this->load->type('tipocomum');
        $this->load->model('setting/setting');

        $data = array(
            'melhorenvio_access_token' => $accessToken,
            'melhorenvio_refresh_token' => $refreshToken,
            'melhorenvio_token_expire' => time() + $tokenExpire,
        );

        $this->model_setting_setting->editSettingForKey('melhorenvio', $data);

        $this->accessToken = $accessToken;
        $this->refreshToken = $refreshToken;
        $this->tokenExpire = $tokenExpire;
    }

    public function getAccess()
    {
        if ($this->config->get('melhorenvio_status') == Type_Status::Tp_Habilitado) {
            if ((!$this->accessToken) || ($this->tokenExpire < time() + 1)) {
                if ($this->refreshToken) {
                    $this->getAccessToken($this->refreshToken);
                    $this->accessToken = trim($this->config->get('melhorenvio_access_token'));
                    $this->tokenExpire = trim($this->config->get('melhorenvio_token_expire'));
                    $this->idClient = trim($this->config->get('melhorenvio_id_client'));
                    $this->keyAccess = trim($this->config->get('melhorenvio_key_access'));
                } else {
                    throw new Exception('Módulo Melhor Envio não autenticado.');
                }
            }
        }
    }

    public function getQuote($dataSend)
    {
        $this->getAccess();
        $header = $this->getHeader();
        $header[] = "Authorization: Bearer " . $this->accessToken;
        $url = $this->getEnvironment() . '/api/v2/me/shipment/calculate';
        $data = parent::callAPI($url, 'POST', $dataSend, $header, false, $retorno);

        if ($data) {
            switch ($retorno) {
                case '200':
                    return $data;
                    break;
                case '401':
                case '403':
                    $error = 'Erro ao carregar módulo Melhor Envio:';
                    is_array($data->message) ? $dataerror = $data->message[0] : $dataerror = $data->message;
                    $error .= 'Código HTTP: ' . $retorno;
                    $error .= 'Mensagem: ' . $dataerror;
                    throw new exception($error);
                    break;
                default :
                    $error = 'Erro ao carregar módulo Melhor Envio:';
                    $error .= 'Mensagem: Erro na conexão com o Melhor Envio';
                    throw new exception($error);
            }
        } else {
            $error = 'Error ao carregar módulo Melhor Envio:';
            $error .= 'Mensagem: Erro na conexão com o Melhor Envio';
            throw new exception($error);
        }

        return $data;
    }

    public function addShippingLabelToCart($dataSend)
    {
        $this->getAccess();
        $header = $this->getHeader();
        $header[] = "Authorization: Bearer " . $this->accessToken;
        $url = $this->getEnvironment() . '/api/v2/me/cart';
        $data = parent::callAPI($url, 'POST', $dataSend, $header, false, $retorno);

        if (isset($data->agency)) {
            return array('error' => 'O campo Agência é obrigatório para a transportadora Jadlog, fazer a configuração no módulo de envio.');
        }

        if (isset($data->error)) {
            return array('error' => $data->error);
        }

        if (isset($data->errors)) {
            $errors = '';
            foreach ($data->errors as $value) {
                if ($errors) {
                    $errors .= ' | ';
                }
                $errors .= implode(',', $value);
            }
            return array('error' => $errors);
        }

        if (isset($data->id)) {
            return $data;
        } else {
            return false;
        }
    }

    public function buyShippingLabel($labelIds)
    {
        $this->getAccess();
        $header = $this->getHeader();
        $header[] = "Authorization: Bearer " . $this->accessToken;
        $url = $this->getEnvironment() . '/api/v2/me/shipment/checkout';
        $param = json_encode(
            array(
                "orders" => $labelIds,
            )
        );
        $data = parent::callAPI($url, 'POST', $param, $header, false, $retorno);

        return $data;
    }

    public function generateShippingLabel($labelIds)
    {
        $this->getAccess();
        $header = $this->getHeader();
        $header[] = "Authorization: Bearer " . $this->accessToken;
        $url = $this->getEnvironment() . '/api/v2/me/shipment/generate';
        $param = json_encode(
            array(
                "orders" => $labelIds,
            )
        );
        $data = parent::callAPI($url, 'POST', $param, $header, false, $retorno);

        return $data;
    }

    public function printShippingLabel($labels)
    {
        $this->getAccess();
        $header = $this->getHeader();
        $header[] = "Authorization: Bearer " . $this->accessToken;
        $url = $this->getEnvironment() . '/api/v2/me/shipment/print';
        $param = json_encode(
            array(
                "mode" => "public",
                "orders" => $labels,
            )
        );

        $data = parent::callAPI($url, 'POST', $param, $header, false, $retorno);

        return $data;
    }

    public function getShippingLabel($labelId)
    {
        $this->getAccess();
        $header = $this->getHeader();
        $header[] = "Authorization: Bearer " . $this->accessToken;
        $url = $this->getEnvironment() . '/api/v2/me/orders/search?q=' . $labelId;
        $data = parent::callAPI($url, 'GET', false, $header, false, $retorno);

        if ($retorno == 200) {
            return $data;
        } else {
            return false;
        }
    }

    public function getTrackingInfo($labelIds)
    {
        $this->getAccess();
        $header = $this->getHeader();
        $header[] = "Authorization: Bearer " . $this->accessToken;
        $url = $this->getEnvironment() . '/api/v2/me/shipment/tracking';
        $param = json_encode(
            array(
                "orders" => $labelIds,
            )
        );
        $data = parent::callAPI($url, 'POST', $param, $header, false, $retorno);

        if ($retorno == 200) {
            return $data;
        } else {
            throw new Exception($data->message);
        }
    }


    public function getAppSetting()
    {
        $this->getAccess();
        $header = $this->getHeader();
        $header[] = "Authorization: Bearer " . $this->accessToken;
        $url = $this->getEnvironment() . '/api/v2/me/shipment/app-settings';

        $data = parent::callAPI($url, 'GET', [], $header, false, $retorno);

        if ($retorno == 200) {
            return $data;
        } else {
            return false;
        }

    }

}