<?php

class ShopeeUtils extends WebServiceMktp
{
    protected $accessToken = null;
    protected $refreshToken = null;
    protected $shopId;
    protected $tokenExpire;
    protected $header;

    const domain_app      = 'https://partner.shopeemobile.com';
    const domain_app_test = 'https://partner.test-stable.shopeemobile.com';

    const shopeeAppId  = '2004336';
    const shopeeAppKey = '85380b88d96ff91fdd84d3068c536d9999a71c4cb166be20d5febf8cb602dca7';

    public function __construct($registry)
    {
        parent::__construct($registry);

        $this->header = array(
            'Accept: application/json;charset=UTF-8',
            'Content-Type: application/json'
        );

        $producao = ($this->config->get('shopee_environment') && ($this->config->get('shopee_environment') == Type_Environment::Tp_Production));

        $this->API_DOMAIN = $producao ? $this::domain_app                    : $this::domain_app_test;
        $this->appId      = $producao ? $this->config->get('shopee_app_id')  : $this->config->get('shopee_app_id_sandbox');
        $this->appSecret  = $producao ? $this->config->get('shopee_app_key') : $this->config->get('shopee_app_key_sandbox');

        $this->refreshToken = trim($this->config->get('shopee_refresh_token'));
        $this->accessToken = trim($this->config->get('shopee_access_token'));
        $this->shopId = trim($this->config->get('shopee_shop_id'));
        $this->tokenExpire = trim($this->config->get('shopee_token_expire'));
    }

    public function callAPI($url, $method = 'GET', $dataSend = false, $header = array(), $file = false, &$httpcode = false, $dataType = Type_DadosSend::TpDados_Identificar, $returnFile = false)
    {
        $httpcode = 0;

        $data = parent::callAPI($url, $method, $dataSend, $header, $file, $httpcode, $dataType, $returnFile);

        if ($httpcode == 0) {
            $this->setErrorShopee($this->error, $url, $method, $dataSend, $data);
            $this->error = ' Connection Error';
        } elseif (($httpcode == 400 || $httpcode == 401 || $httpcode == 403 || $httpcode == 404 || $httpcode == 405 || $httpcode == 406 || $httpcode == 407 || $httpcode == 409 || $httpcode == 410 || $httpcode == 500 || $httpcode == 501 || $httpcode == 502)
            || (isset($data->error) && $data->error)){
            $msgErro = '';
            $msgErro .= (isset($data->error) && $data->error) ? 'Erro: '.$data->error.PHP_EOL : '';
            $msgErro .= (isset($data->message) && $data->message) ? 'Mensagem: '.$data->message.PHP_EOL : '';
            $this->error = $msgErro ? $msgErro : 'Erro não identificado';
        } else {
            return $data;
        }
    }

    public function getSign($apiPath, $timestamp, $withToken = true)
    {
        if ($withToken){
            $baseString = $this->appId . $apiPath . $timestamp . $this->accessToken . $this->shopId;
        } else {
            $baseString = $this->appId . $apiPath . $timestamp;
        }
        return hash_hmac('sha256', $baseString, $this->appSecret);
    }

    public function getSignURL($apiPath, $withToken = true)
    // Adiciona os parametros Sign e Timestamp na URL
    {
        $dateTimestamp = (new DateTime())->getTimestamp();
        $sign = $this->getSign($apiPath, $dateTimestamp, $withToken);

        return '&sign=' . $sign . '&timestamp=' . $dateTimestamp;
    }

    public function setErrorShopee($error, $url = '', $method = '', $data = '', $body = '')
    {
        if ($this->config->get('shopee_debug')) {
            $error_msg = 'Error =>' . $error . PHP_EOL;
            $error_msg .= (!empty($url)) ? 'Url => ' . $url . PHP_EOL : '';
            $error_msg .= (!empty($method)) ? 'Metodo => ' . $method . PHP_EOL : '';
            $error_msg .= (!empty($data)) ? 'Data => ' . print_r($data, true) . PHP_EOL : '';
            $error_msg .= (!empty($body)) ? 'Body => ' . print_r($body, true) . PHP_EOL : '';
            $error_msg .= '-----------------------------------------------------------------------------------------------';
            $this->logshopee->write($error_msg);
        }
    }

    public function getAccess()
    {
        if($this->config->get('shopee_status') == Type_Status::Tp_Habilitado){
            if ((!$this->accessToken) || ($this->tokenExpire < time() + 1)) {

                $refreshToken = $this->refreshAccessToken();
                if ($refreshToken === false){
                    throw new exception($this->error);
                }

                $expireTime = (new DateTime())->getTimestamp() + $refreshToken->expire_in;

                $this->refresh_token = trim($refreshToken->refresh_token);
                $this->accessToken = trim($refreshToken->access_token);
                $this->shopId = trim($refreshToken->shop_id);
                $this->tokenExpire = $expireTime;
            }
        }
    }

    public function getAccessToken($code, $shopId){
        $apiPath = '/api/v2/auth/token/get';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . $this->getSignURL($apiPath, false);

        $param = array(
            "code" => $code,
            "partner_id" => (integer)$this->appId,
            "shop_id" => (integer)$shopId,
        );

        $param = json_encode($param);

        $data = $this->callAPI($url, 'POST', $param, $this->header, false, $httpcode);

        if ($this->error) {
            return $this->error;
        } else {
            if (is_object($data) && property_exists($data, 'access_token')) {
                $this->load->model('setting/setting');
                $expireTime = (new DateTime())->getTimestamp() + $data->expire_in;


                $tokenInfo = array(
                    'shopee_refresh_token' => $data->refresh_token,
                    'shopee_access_token' => $data->access_token,
                    'shopee_shop_id' => $shopId,
                    'shopee_token_expire' => $expireTime,
                );

                $this->refresh_token = trim($data->refresh_token);
                $this->accessToken = trim($data->access_token);
                $this->shopId = trim($shopId);
                $this->tokenExpire = $expireTime;

                $this->model_setting_setting->editSettingForKey('shopee', $tokenInfo);
            }
            return $data;
        }
    }

    public function refreshAccessToken(){
        $apiPath = '/api/v2/auth/access_token/get';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . $this->getSignURL($apiPath, false);

        $param = array(
            "refresh_token" => $this->refreshToken,
            "partner_id" => (integer)$this->appId,
            "shop_id" => (integer)$this->shopId,
        );

        $param = json_encode($param);

        $data = $this->callAPI($url, 'POST', $param, $this->header, false, $httpcode);

        if ($this->error) {
            return false;
        } else {
            if (is_object($data) && property_exists($data, 'access_token')) {
                $this->load->model('setting/setting');
                $expireTime = (new DateTime())->getTimestamp() + $data->expire_in;

                $tokenInfo = array(
                    'shopee_refresh_token' => $data->refresh_token,
                    'shopee_access_token' => $data->access_token,
                    'shopee_shop_id' =>  $data->shop_id,
                    'shopee_token_expire' => $expireTime,
                );

                $this->model_setting_setting->editSettingForKey('shopee', $tokenInfo);
            }
            return $data;
        }
    }

    public function validateAccess(){
        try {
            $this->getAccess();
        } catch (Exception $exception) {
            return false;
        }

        $apiPath = '/api/v2/shop/get_shop_info';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . $this->getSignURL($apiPath);

        $data = $this->callAPI($url, 'GET', false, $this->header, false, $httpcode);

        $result = ['success' => (is_object($data) && property_exists($data, 'shop_name'))];
        if (strpos($this->error, 'No permission. Please inform seller to complete the Seller Registration on Shopee Seller Center first')){
            $result['message'] = 'É necessário completar o cadastro de vendedor no painel da Shopee';
        }
        return $result;
    }

    public function getProductCategories($parentId = false)
    {
        $categories = $this->cache->get('shopee_product_categories');

        if (!$categories) {
            $this->getAccess();

            $apiPath = '/api/v2/product/get_category';

            $url = $this->API_DOMAIN . $apiPath
                . '?partner_id=' . $this->appId
                . '&access_token=' . $this->accessToken
                . '&shop_id=' . $this->shopId
                . '&language=pt-br'
                . $this->getSignURL($apiPath);

            $response = $this->callAPI($url, 'GET');

            if (!$this->error) {
                $categories = $response->response->category_list;
                $this->cache->set('shopee_product_categories', $categories, 14400 /* valor em segundos(4 horas) */);
            } else {
                throw new exception('Erro ao procurar categorias da Shopee.' . PHP_EOL . 'Erro: ' . $this->error);
            }
        }

        if ($parentId === false){
            return $categories;
        } else {
            return array_filter($categories, function ($value) use ($parentId){
                return $value->parent_category_id == $parentId;
            });
        }
    }

    public function getCategoryAttributes($categoryId)
    {
        $attributes = $this->cache->get('shopee_category_attributes.' . $categoryId);

        if (!$attributes) {
            $this->getAccess();

            $apiPath = '/api/v2/product/get_attributes';

            $url = $this->API_DOMAIN . $apiPath
                . '?partner_id=' . $this->appId
                . '&access_token=' . $this->accessToken
                . '&shop_id=' . $this->shopId
                . '&language=pt-br'
                . '&category_id=' . $categoryId
                . $this->getSignURL($apiPath);

            $response = $this->callAPI($url, 'GET');

            if (!$this->error) {
                $attributes = $response->response->attribute_list ?? [];
                $this->cache->set('shopee_category_attributes.' . $categoryId, $attributes, 14400 /* valor em segundos(4 horas) */);
            }
        }

        return $attributes;
    }

    public function getCategoryBrands($categoryId, $status, $offset)
    {
        $this->getAccess();

        $apiPath = '/api/v2/product/get_brand_list';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . '&language=pt-br'
            . '&page_size=100'
            . '&category_id=' . $categoryId
            . '&status=' . $status
            . '&offset=' . $offset
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url, 'GET');

        if (!$this->error) {
            return $response->response;
        } else {
            return false;
        }
    }

    public function getAllCategoryBrands($categoryId)
    {
        $brands = $this->cache->get('shopee_category_brands.' . $categoryId);

        if (!$brands) {
            // Shopee obriga a passar status, porém eu preciso das duas listas :[
            $brandsApproved = $this->getAllCategoryBrandsByStatus($categoryId, Type_ShopeeBrandStatus::Tp_Approved);
            $brandsRevision = $this->getAllCategoryBrandsByStatus($categoryId, Type_ShopeeBrandStatus::Tp_InRevision);

            $brands = array_merge($brandsApproved, $brandsRevision) ?? [];
            if (!empty($brands)) {
                $this->cache->set('shopee_category_brands.' . $categoryId, $brands, 86400 /* valor em segundos(1 dia) */);
            }
        }

        return $brands;
    }

    public function getAllCategoryBrandsByStatus($categoryId, $status){
        $brands = [];
        $offset = 0;
        do{
            $response = $this->getCategoryBrands($categoryId, $status, $offset);
            if ($response) {
                $brands = array_merge($brands, $response->brand_list);
                $offset = $response->next_offset;
            }
        } while ($response && $response->has_next_page);
        return $brands;
    }

    public function getLogisticChannels()
    {
        $logisticChannels = $this->cache->get('shopee_logistic_channels');

        if (!$logisticChannels) {
            $this->getAccess();

            $apiPath = '/api/v2/logistics/get_channel_list';

            $url = $this->API_DOMAIN . $apiPath
                . '?partner_id=' . $this->appId
                . '&access_token=' . $this->accessToken
                . '&shop_id=' . $this->shopId
                . $this->getSignURL($apiPath);

            $response = $this->callAPI($url, 'GET');

            if (!$this->error) {
                $logisticChannels = $response->response->logistics_channel_list ?? [];
                $this->cache->set('shopee_logistic_channels', $logisticChannels, 86400 /* valor em segundos(1 dia) */);
            }
        }

        return $logisticChannels;
    }

    public function uploadImage($image)
    {
        $this->getAccess();

        $apiPath = '/api/v2/media_space/upload_image';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . $this->getSignURL($apiPath, false);

        $image = $this->makeCurlFile($image);

        $datasend = array (
            'image' => $image
        );

        $response = $this->callAPI($url, 'POST', $datasend, '',true);

        if (!$this->error) {
            return $response->response->image_info->image_id ?? [];
        } else {
            return false;
        }
    }

    public function addProduct($datasend)
    {
        $this->getAccess();

        $apiPath = '/api/v2/product/add_item';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url, 'POST', $datasend, $this->header, false, $retorno, Type_DadosSend::TpDados_Json);

        if (!$this->error) {
            return $response->response;
        } else {
            return false;
        }
    }

    public function updateProduct($productID, $datasend)
    {
      $pridutStaus = $this->getProduct($productID);

      if(isset($pridutStaus->item_status) and $this->validateStatus($pridutStaus->item_status)){
        $this->getAccess();

        $apiPath = '/api/v2/product/update_item';

        $url = $this->API_DOMAIN . $apiPath
          . '?partner_id=' . $this->appId
          . '&access_token=' . $this->accessToken
          . '&shop_id=' . $this->shopId
          . $this->getSignURL($apiPath);

        $datasend['item_id'] = (integer)$productID;

        $response = $this->callAPI($url, 'POST', $datasend, $this->header, false, $retorno, Type_DadosSend::TpDados_Json);

        if (!$this->error) {
          return $response->response;
        } else {
          return false;
        }
      }else{
        return false;
      }
    }

    public function addProductModel($datasend)
    {
        $this->getAccess();

        $apiPath = '/api/v2/product/add_model';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url, 'POST', $datasend, $this->header, false, $retorno, Type_DadosSend::TpDados_Json);

        if (!$this->error) {
            return $response->response;
        } else {
            return false;
        }
    }

    public function updateProductModel($datasend)
    {
        $this->getAccess();

        $apiPath = '/api/v2/product/update_model';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url, 'POST', $datasend, $this->header, false, $retorno, Type_DadosSend::TpDados_Json);

        if (!$this->error) {
            return $response->response;
        } else {
            return false;
        }
    }

    private function validateStatus($status){
      switch ($status){
        case 'NORMAL': return true; break;
        case 'UNLIST': return true; break;
        default :
          throw new exception("Operação permitida apenas para status NORMAL ou UNLIST "
            . "Status Atual: " . $status);
          return false;
      }
    }

    public function updateProductStock($productID, $stock, $variations = false)
    {
      $pridutStaus = $this->getProduct($productID);

      if(isset($pridutStaus->item_status) and $this->validateStatus($pridutStaus->item_status)){
        $this->getAccess();

        $apiPath = '/api/v2/product/update_stock';

        $url = $this->API_DOMAIN . $apiPath
          . '?partner_id=' . $this->appId
          . '&access_token=' . $this->accessToken
          . '&shop_id=' . $this->shopId
          . $this->getSignURL($apiPath);

        $datasend = array (
          'item_id' => (integer)$productID,
        );

        $stock_list = array();
        if ($variations){
          foreach ($variations as $value){
            $quantity = $value->getQuantity();
            if ($value->getStatus() == Type_Status::Tp_Desabilitado){
              if (empty($value->getMktVariation_id())) {
                continue;
              } else {
                $quantity = 0;
              }
            }
            $stock_list[] = [
              'model_id' => (integer)$value->getMktVariation_id(),
              'seller_stock' => [['stock' => (integer)$quantity]]
            ];
          }
        } else {
          $stock_list[] = [
            'seller_stock' => [['stock' => (integer)$stock]]
          ];
        }

        $datasend['stock_list'] = $stock_list;

        $response = $this->callAPI($url, 'POST', $datasend, $this->header, false, $retorno, Type_DadosSend::TpDados_Json);

        if (!$this->error) {
          return $response->response;
        } else {
          return false;
        }
      }else{
        return false;
      }
    }

    public function updateProductPrice($productID, $price, $variations = false)
    {
      $pridutStaus = $this->getProduct($productID);

      if($this->validateStatus($pridutStaus->item_status)) {
        $this->getAccess();

        $apiPath = '/api/v2/product/update_price';

        $url = $this->API_DOMAIN . $apiPath
          . '?partner_id=' . $this->appId
          . '&access_token=' . $this->accessToken
          . '&shop_id=' . $this->shopId
          . $this->getSignURL($apiPath);

        $datasend = array(
          'item_id' => (integer)$productID,
        );

        if ($variations) {
          foreach ($variations as $value) {
            if ($value->getStatus() == Type_Status::Tp_Desabilitado) {
              continue;
            }
            $price_list[] = [
              'model_id' => (integer)$value->getMktVariation_id(),
              'original_price' => (float)$value->getValor()
            ];
          }
        } else {
          $price_list = [[
            'original_price' => (float)$price
          ]];
        }

        if (empty($price_list)) {
          return true;
        }
        $datasend['price_list'] = $price_list;

        $response = $this->callAPI($url, 'POST', $datasend, $this->header, false, $retorno, Type_DadosSend::TpDados_Json);

        if (!$this->error) {
          return $response->response;
        } else {
          return false;
        }
      }else{
        return false;
      }
    }

    public function getProduct($itemId)
    {
        $this->getAccess();

        $apiPath = '/api/v2/product/get_item_base_info';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . '&need_tax_info=false'
            . '&need_complaint_policy=false'
            . '&item_id_list=' . (integer)$itemId
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url);

        if (!$this->error) {
            return current($response->response->item_list);
        } else {
            return false;
        }
    }

    public function getProductVariations($itemId)
    {
        $this->getAccess();

        $apiPath = '/api/v2/product/get_model_list';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . '&item_id=' . (integer)$itemId
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url);

        if (!$this->error) {
            return $response->response;
        } else {
            return false;
        }
    }

    public function mountProductVariations($variations)
    {
        $result = [];
        if (!empty($variations)) {
            foreach ($variations->model as $model) {
                $object = [];

                $variationDescription = '';
                foreach ($model->tier_index as $key => $tier) {
                    $variationDescription .= (empty($variationDescription) ? '' : ' - ') . $variations->tier_variation[$key]->name . ': ' . $variations->tier_variation[$key]->option_list[$tier]->option;
                }

                $object = [
                    'model_id' => $model->model_id,
                    'description' => $variationDescription,
                    'price' => current($model->price_info)->current_price,
                    'formated_price' => $this->currency->format(current($model->price_info)->current_price) ,
                    'stock' => $model->stock_info_v2->summary_info->total_available_stock,
                ];

                $result[] = $object;
            }
        }
        return $result;
    }

    public function delete($itemId)
    {
        $this->getAccess();

        $apiPath = '/api/v2/product/delete_item';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . $this->getSignURL($apiPath);

        $datasend = [
            'item_id' => (integer)$itemId
        ];

        $response = $this->callAPI($url, 'POST', $datasend, $this->header, false, $retorno, Type_DadosSend::TpDados_Json);

        return $response;
    }

    public function addTierVariation($datasend)
    {
        $this->getAccess();

        $apiPath = '/api/v2/product/init_tier_variation';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url, 'POST', $datasend, $this->header, false, $retorno, Type_DadosSend::TpDados_Json);

        if (!$this->error) {
            return $response->response;
        } else {
            return false;
        }
    }

    public function updateTierVariation($datasend)
    {
        $this->getAccess();

        $apiPath = '/api/v2/product/update_tier_variation';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url, 'POST', $datasend, $this->header, false, $retorno, Type_DadosSend::TpDados_Json);

        if (!$this->error) {
            return $response;
        } else {
            return false;
        }
    }

    // Order
    public function getOrderList($datasend)
    {
        $this->getAccess();

        $apiPath = '/api/v2/order/get_order_list';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . '&time_range_field=' . $datasend['time_range_field']
            . '&time_from=' . $datasend['time_from']
            . '&time_to=' . $datasend['time_to']
            . '&page_size=' . $datasend['page_size']
            . $this->getSignURL($apiPath);

        if (isset($datasend['cursor'])){
            $url .= '&cursor=' . $datasend['cursor'];
        }

        if (isset($datasend['order_status'])){
            $url .= '&order_status=' . $datasend['order_status'];
        }

        $response = $this->callAPI($url, 'GET', false, $this->header, false, $retorno);

        if (!$this->error) {
            return $response->response;
        } else {
            return false;
        }
    }

    public function getOrderMarketplace($orders_id)
    {
        $this->getAccess();

        $metodo = 'GET';
        $apiPath = '/api/v2/order/get_order_detail';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . $this->getSignURL($apiPath);
        if (is_array($orders_id)){
            $datasend = ['order_sn_list' => implode(",", $orders_id)];
        } else {
            $datasend = ['order_sn_list' => $orders_id];
        }
        $url .= '&order_sn_list=' . $datasend['order_sn_list'];
        $url .= '&response_optional_fields=total_amount,payment_method,shipping_carrier,estimated_shipping_fee,buyer_user_id,buyer_username,recipient_address,item_list,buyer_cpf_id';

        $response = $this->callAPI($url, $metodo, false, $this->header, false, $retorno);

        if (!$this->error) {
            if (is_array($orders_id)) {
                return $response->response->order_list;
            } else {
                $retorno = current($response->response->order_list);
                if ($retorno instanceOf StdClass) {
                    $this->marketplace->logArray[] = array('tipoEnviado' => Type_LogEnviado::Tp_LogRecebido, 'tipoIntegracao' => Type_MarketPlace::Tp_Shopee,
                        'origem' => __METHOD__, 'tipoLog' => Type_Log::Tp_LogPedido, 'tipoId' => Type_LogId::Tp_LogIdMktPedido, 'entidadeId' => $retorno->order_sn ?? '',
                        'url' => $url, 'metodo' => $metodo, 'httpCode' => $this->httpcode, 'retorno' => $retorno, 'dataHora' => $this->db->dataAtual());
                }
                return $retorno;
            }
        } else {
            return false;
        }
    }

    public function getPaymentDetails($order_id)
    {
        $this->getAccess();

        $metodo = 'GET';
        $apiPath = '/api/v2/payment/get_escrow_detail';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . '&order_sn=' . $order_id
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url, $metodo, false, $this->header, false, $retorno);

        if (!$this->error) {
            return $response->response;
        } else {
            return false;
        }
    }

    public function getTrackingInfo($order_id)
    {
        $this->getAccess();

        $metodo = 'GET';
        $apiPath = '/api/v2/logistics/get_tracking_info';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . '&order_sn=' . $order_id
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url, $metodo, false, $this->header, false, $retorno);

        if (!$this->error) {
            return $response->response;
        } else {
            return false;
        }
    }

    public function getTrackingNumber($order_id)
    {
        $this->getAccess();

        $metodo = 'GET';
        $apiPath = '/api/v2/logistics/get_tracking_number';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . '&order_sn=' . $order_id
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url, $metodo, false, $this->header, false, $retorno);

        if (!$this->error) {
            return $response->response;
        } else {
            return false;
        }
    }

    public function addInvoiceData($mktOrderId, $datasend)
    {
        $this->getAccess();

        $apiPath = '/api/v2/order/upload_invoice_doc';
        $metodo = 'POST';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url, $metodo, $datasend, [], true, $retorno);

        $this->marketplace->logArray[] = array('tipoEnviado' => Type_LogEnviado::Tp_LogEnviado, 'tipoIntegracao' => Type_MarketPlace::Tp_Shopee,
            'origem' => __METHOD__, 'tipoLog' => Type_Log::Tp_LogPedido, 'tipoId' => Type_LogId::Tp_LogIdMktPedido, 'entidadeId' => $mktOrderId,
            'url' => $url, 'metodo' => $metodo, 'httpCode' => $this->httpcode, 'retorno' => ($this->error) ? $this->error : $response, 'enviado' => $datasend, 'dataHora' => $this->db->dataAtual());

        return [
            'success' => (boolean)!$this->error,
            'erro' => $this->error ?? '',
        ];
    }

    public function getShippingParameter($order_id)
    {
        $this->getAccess();

        $metodo = 'GET';
        $apiPath = '/api/v2/logistics/get_shipping_parameter';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . '&order_sn=' . $order_id
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url, $metodo, false, $this->header, false, $retorno);

        if (!$this->error) {
            return $response->response;
        } else {
            return false;
        }
    }

    public function shipOrder($mktOrderId, $datasend)
    {
        $this->getAccess();

        $apiPath = '/api/v2/logistics/ship_order';
        $metodo = 'POST';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url, $metodo, $datasend, $this->header, false, $retorno, Type_DadosSend::TpDados_Json);

        $this->marketplace->logArray[] = array('tipoEnviado' => Type_LogEnviado::Tp_LogEnviado, 'tipoIntegracao' => Type_MarketPlace::Tp_Shopee,
            'origem' => __METHOD__, 'tipoLog' => Type_Log::Tp_LogPedido, 'tipoId' => Type_LogId::Tp_LogIdMktPedido, 'entidadeId' => $mktOrderId,
            'url' => $url, 'metodo' => $metodo, 'httpCode' => $this->httpcode, 'retorno' => ($this->error) ? $this->error : $response, 'enviado' => $datasend, 'dataHora' => $this->db->dataAtual());

        return [
            'success' => (boolean)!$this->error,
            'erro' => $this->error ?? '',
        ];
    }

    // Sera feito depois porque funciona em um outro padrão, e não temos tempo agora
    /*
    public function setCancelOrder($mktOrderId)
    {
        $this->getAccess();

        $apiPath = '/api/v2/order/cancel_order';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&access_token=' . $this->accessToken
            . '&shop_id=' . $this->shopId
            . $this->getSignURL($apiPath);

        $response = $this->callAPI($url, 'POST', $datasend, $this->header, false, $retorno, Type_DadosSend::TpDados_Json);

        if (!$this->error) {
            return $response;
        } else {
            return false;
        }
    }
    */


    public function shipingDocument($id, $datasend){
      //TODO etiqueta Função não operante
      $this->getAccess();

      $apiPath = '/api/v2/logistics/download_shipping_document';
      $metodo = 'POST';

      $url = $this->API_DOMAIN . $apiPath
        . '?partner_id=' . $this->appId
        . '&access_token=' . $this->accessToken
        . '&shop_id=' . $this->shopId
        . $this->getSignURL($apiPath);

      $response = $this->callAPI($url, $metodo, json_encode($datasend), $this->header, false, $retorno, Type_DadosSend::TpDados_Json);

      $this->marketplace->logArray[] = array('tipoEnviado' => Type_LogEnviado::Tp_LogEnviado, 'tipoIntegracao' => Type_MarketPlace::Tp_Shopee,
        'origem' => __METHOD__, 'tipoLog' => Type_Log::Tp_LogPedido, 'tipoId' => Type_LogId::Tp_LogIdMktPedido, 'entidadeId' => $mktOrderId,
        'url' => $url, 'metodo' => $metodo, 'httpCode' => $this->httpcode, 'retorno' => ($this->error) ? $this->error : $response, 'enviado' => $datasend, 'dataHora' => $this->db->dataAtual());

      return [
        'success' => (boolean)!$this->error,
        'erro' => $this->error ?? '',
      ];

    }

    public function orderJsonToObject($jsonOrder, $jsonPaymentOrder)
    {
        $this->load->helper('ftr_validacao');
        $buyer = new MktBuyer();
        $buyerSendAdd = new MktAddress();
        $pedido = new MktPedido();

        if (ftr_validacao::isCpf($jsonOrder->buyer_cpf_id)) {
            $tipo_doc = Type_Pessoa::TpPess_fisica;
        } elseif (ftr_validacao::isCnpj($jsonOrder->buyer_cpf_id)) {
            $tipo_doc = Type_Pessoa::TpPess_Juridica;
        } else {
            $tipo_doc = Type_Pessoa::TpPess_naoInformado;
        }

        $username = $jsonOrder->buyer_username;
        $name = $jsonOrder->recipient_address->name;
        $lastName = '';

        $buyerId = $jsonOrder->buyer_user_id;

        $splitName = explode(' ', $name);
        $firstname = substr($name, 0, (count($splitName) > 1 ? strlen($name)-strlen($splitName[count($splitName)-1])-1 : strlen($name)));

        if ((count($splitName) > 1) && isset($splitName[count($splitName)-1])) {
            $lastName = $splitName[count($splitName)-1];
        }

        $lastName .= '(Nick: '.$username.')';

        $phone   = "";
        $celular = "";

        if (isset($jsonOrder->recipient_address->phone) && (strpos($jsonOrder->recipient_address->phone, '****') === false)) {
            $phoneNumber = $jsonOrder->recipient_address->phone;
            if ($phoneNumber >= 12){
                $phoneNumber = substr($phoneNumber, 2, strlen($phoneNumber)-2);
            }
            $phoneNumber = preg_replace('/[^0-9]/', '', $phoneNumber);

            if (strlen($phoneNumber) <= 10) {
                $phone = $phoneNumber;
            } else {
                $celular = $phoneNumber;
            }
        }

        $buyer
            //->setEmail($jsonOrder->user->email)
            ->setDocumento($jsonOrder->buyer_cpf_id)
            ->setTipoPessoa($tipo_doc)
            ->setNick($username)
            ->setMktBuyerId($buyerId)
            ->setFirstName($firstname)
            ->setLastName($lastName)
            ->setPhone($phone)
            ->setCelular($celular);

        $fullAddress = $jsonOrder->recipient_address->full_address;
        $logradouro = substr($fullAddress, 0, strpos($fullAddress, ','));
        $postcode = substr(preg_replace('/[^0-9]/', '', $jsonOrder->recipient_address->zipcode),-8);

        // agora eu vou tentar pegar o as partes do endereço de um jeito ruim, porque a shopee não me retorna os campos separado :[
        $fullAddressArray = explode(',', $fullAddress);
        $addressNumber = $fullAddressArray[1] ?? 0;
        $complemento = '';
        // se tem 6 itens, o terceiro é o complemento
        if (count($fullAddressArray) == 6) {
            $complemento = $fullAddressArray[2];
        }

        $buyerSendAdd
            ->setUf($jsonOrder->recipient_address->state)
            ->setPostCode($postcode)
            ->setPais('BR')
            ->setBairro($jsonOrder->recipient_address->district)
            ->setCidade($jsonOrder->recipient_address->city)
            ->setLogradouroTipo('')
            ->setLogradouro($logradouro);

        // se tiver virgula ele tira e trata igual era antes
        if (strpos($addressNumber, ',') !== false) {
            $addressNumber = str_replace(',','', $addressNumber);
        }
        if (is_numeric($addressNumber)) {
            $buyerSendAdd->setNumero($addressNumber);
        } else {
            $buyerSendAdd->setNumero(0);

            $complemento = $addressNumber . ', ' . $complemento;
        }
        $buyerSendAdd->setComplemento($complemento);

        $buyer->setSendAddress($buyerSendAdd);
        $buyer->setBillingAddress($buyerSendAdd);

        $discount = $jsonPaymentOrder->voucher_from_seller + $jsonPaymentOrder->seller_discount;
        $shopee_discount = $jsonPaymentOrder->shopee_discount + $jsonPaymentOrder->voucher_from_shopee;
        $shipping_cost = $jsonPaymentOrder->final_shipping_fee *-1;
        $pedido
            ->setMktId($jsonOrder->order_sn)
            ->setDateCreated($jsonOrder->create_time)
            ->setShippingCost($shipping_cost)
            ->setShippingName($jsonOrder->shipping_carrier)
            ->setmktIntegration(Type_MarketPlace::Tp_Shopee)
            ->setMkTipo(Type_MarketplaceInt::Tp_Shopee)
            ->setAddressCombinar(false)
            ->setBuyer($buyer)
            ->setParam('status', $jsonOrder->order_status)
            ->setDiscount($discount)
            ->setParam('shopee_discount', $shopee_discount);

        $subTotal = 0;
        foreach ($jsonOrder->item_list as $item) {
            $itemObj = new MktPedidoItem();

            $itemObj
                ->setMktId($item->item_id)
                ->setPrice($item->model_discounted_price)
                ->setSku($item->item_sku)
                ->setProductName($item->item_name)
                ->setQuantity($item->model_quantity_purchased)
                ->setMktVariationId($item->model_id > 0 ? $item->model_id : null)
                ->setMktIdOrderItem($item->order_item_id);

            $pedido->addItens($itemObj);
            $subTotal += ($item->model_original_price * $item->model_quantity_purchased);
        }

        $pedido->setSubTotal($subTotal);
        return $pedido;
    }

}
