<?php

final class Shopee extends ShopeeUtils
{

    public function getLoginUrl()
    {
        $apiPath = '/api/v2/shop/auth_partner';
        $dateTimestamp = (new DateTime())->getTimestamp();
        $sign = $this->getSign($apiPath, $dateTimestamp, false);
        $urlRedirectLoja = $this->urlloja->link('', '', 'NONSSL', false) . 'shopeeauth';

        $url = $this->API_DOMAIN . $apiPath
            . '?partner_id=' . $this->appId
            . '&redirect=' . $urlRedirectLoja/*ftr_geral::base64url_encode($urlRedirectLoja)*/
            . '&sign=' . $sign
            . '&timestamp=' . $dateTimestamp;
        return $url;
    }

    public function mountProductMktRetorno($productData, $variationsData = false)
    {
        $productReturn = new MktProdutoRetorno();
        $productReturn->setmktIntegrationId($productData->item_id);
        $productReturn->setmktName($productData->item_name);
        $productReturn->setmktLink('');
        $productReturn->setmktTipo(Type_MarketPlace::Tp_Shopee);
        $productReturn->setmktStatus($productData->item_status);

        if ($variationsData) {
            $productReturn->setmktVariations($variationsData);
            $productReturn->setProductType(Type_ProdutoMkt::Tp_MktProd_Grade);
        } else {
            $productReturn->setProductType(Type_ProdutoMkt::Tp_MktProd_Normal);
            $productReturn->setmktPrice($productData->price_info->current_price ?? current($productData->price_info)->current_price);
            $productReturn->setmktQuantity($productData->stock_info->current_stock ?? current($productData->stock_info)->current_stock);

        }

        return $productReturn;
    }

    public function getProduto($mktplace_id)
    {
        $productMktData = $this->getProduct($mktplace_id);

        $productVariationsMktData = false;
        if ($productMktData) {
            if ($productMktData->has_model){
                $productVariationsMktData = $this->getProductVariations($mktplace_id);
            }
            return $this->mountProductMktRetorno($productMktData, $productVariationsMktData);
        } else {
            throw new exception($this->error);
        }
    }

    public function setAtualizarEstoqueFromProdutos(MktProduto $produto, MktProdutoRetorno $produtoRetorno)
    {
        $variacoes = $produto->hasVariations() ? $produto->getVariacao() : false;
        $retorno = $this->updateProductStock($produtoRetorno->getMktIntegrationId(), $produto->getQuantity(), $variacoes);

        if ($retorno) {
            $produto->setMktRetorno($this->getProduto($produtoRetorno->getMktIntegrationId()));
            return $produto;
        } else {
            throw new exception($this->error);
        }

    }

    public function setAtualizarEstoque(MktProduto $produto, $mkt_product_id)
    {
        $produtoRetorno = $this->getProduto($mkt_product_id);
        return $this->setAtualizarEstoqueFromProdutos($produto, $produtoRetorno);
    }

    public function setAtualizarEstoquePreco(MktProduto $produto)
    {
        $variacoes = $produto->hasVariations() ? $produto->getVariacao() : false;

        if (!$this->updateProductStock($produto->getMktId(), $produto->getQuantity(), $variacoes)) {
            throw new exception($this->error);
        }

        if (!$this->updateProductPrice($produto->getMktId(), $produto->getPrice(), $variacoes)) {
            throw new exception($this->error);
        }

        $result = $this->getProduto($produto->getMktId());
        $produto->setMktRetorno($result);
        return $produto;
    }

    private function getVariationOptions($variation, &$variationAttributes, $variationName, $variationTemplate, $variationValue){
        if ($variationValue !== null){
            if (!in_array($variationTemplate, $variationAttributes)) {
                $variationAttributes[$variationName]['name'] = $variationTemplate;
            }

            if((!isset($variationAttributes[$variationName]['options'])) || (!in_array($variationValue, array_column($variationAttributes[$variationName]['options'], 'value')))) {
//                $variationAttributes[$variationName]['options'][] = $variationValue;
                $optionObject = ['value' => $variationValue];

                // só envia imagem do primeiro tier
                $sendImage = ($variation) && !empty($variation->getImagens()->getImagens()) && (empty($variationAttributes) || $variationName == array_keys($variationAttributes)[0]);
                if ($sendImage){
                    $img = current($variation->getImagens()->getImagens());
                    if ((!$img->getImageMktId()) || ($img->getIdFutura() != $img->getMktIdFutura())){
                        $mktImageId = $this->uploadImage($img->getImgPath());
                        if ($mktImageId) {
                            $img->setImageMktId($mktImageId);
                            $img->setMktIdFutura($img->getIdFutura());
                            if ($img->getId() == 0) {
                                $this->dmodel_marketplace_marketplace->saveMarketplaceProductImageFkProduct(Type_MarketPlace::Tp_Shopee, $variation->getSku(), $mktImageId, $img->getIdFutura());
                            } else {
                                $this->dmodel_marketplace_marketplace->saveMarketplaceProductImageFkImage(Type_MarketPlace::Tp_Shopee, $img->getId(), $mktImageId, $img->getIdFutura());
                            }
                            $image_id = $mktImageId;
                        } else {
                            throw new exception($this->error);
                        }
                    } else {
                        $image_id = $img->getImageMktId();
                    }
                    $optionObject['image'] = $image_id;
                }

                $variationAttributes[$variationName]['options'][] = $optionObject;
            }
        }
    }

    public function setAtualizarProduto(MktProduto $produto, $data = array())
    {
        $this->load->helper('ftr_geral');
        $this->load->model('setting/setting');
        $this->load->dmodel('marketplace/marketplace');
        $this->load->dmodel('shopee/shopeeproduto');

        if ($produto->getParam('link_type') == Type_MarketplaceLink::Tp_Stock){
            throw new exception("Vinculo do produto é apenas de estoque, não deve sobrescrever as informações do anúncio, contate a Futura Sistemas."
                . "Produto ID: " . $produto->getProductid());
        }

        $addedProduct = false;

        $title = $produto->getCustomTitle();
        if ((!isset($title)) || (empty($title))) {
            $title = $produto->getName();
        }

        $initial_description = $this->config->get('shopee_initial_description') ?? '';
        $final_description = $this->config->get('shopee_final_description') ?? '';

        trim($initial_description) != '' ? $initial_description = trim($initial_description) . "\n\n" : $initial_description = '';
        trim($final_description) != '' ? $final_description = trim($final_description) : $final_description = '';
        if (!empty($final_description) && !empty($produto->getDescription())) {
            $final_description = "\n\n" . $final_description;
        }

        $description = $initial_description . $produto->getDescription() . $final_description;

        $jsonSend = array();

        $enviado = true;

        if ($produto->getPrice() <= 0) {
            throw new exception("Não é possivel sincronizar produtos com o preço negativo ou igual a 0!");
        }

        $pricePer = floatval($produto->getPrice());

        $category_id = $produto->getParam('category_id');

        $attributes  = $produto->getParam('attributes');
        $attribute_list  = [];
        foreach ($attributes as $value){
            if ((integer)$value['attribute_id'] === 0){
                continue;
            }
            $attribute_value_list = [];
            $attribute_value_list[] = [
                'value_id' => (integer)$value['value_id'],
                'original_value_name' => $value['value_name']
            ];
            if ($value['value_unit']){
                $attribute_value_list[0]['value_unit'] = $value['value_unit'];
            }
            $attribute_list[] = [
                'attribute_id' => (integer)$value['attribute_id'],
                'attribute_value_list' => $attribute_value_list,
            ];
        }

        $logistic_list  = [];
        foreach ($produto->getParam('shipping') as $value){
            $logistic_list[] = [
                'logistic_id' => (integer)$value,
                'enabled' => true,
            ];
        }

        // Faz upload das imagens do produto e salva na base
        $image_list = [];
        $imagesProd = $produto->getPictures()->getImagens();
        if ($imagesProd) {
            foreach ($imagesProd as $value) {
                if ($produto->hasVariations() && $value->getId() != 0){
                    continue;
                }
                if ((!$value->getImageMktId()) || ($value->getIdFutura() != $value->getMktIdFutura())){
                    $mktImageId = $this->uploadImage($value->getImgPath());
                    if ($mktImageId) {
                        $value->setImageMktId($mktImageId);
                        $value->setMktIdFutura($value->getIdFutura());
                        $image_list[] = $mktImageId;
                        if ($value->getId() == 0) {
                            $this->dmodel_marketplace_marketplace->saveMarketplaceProductImageFkProduct(Type_MarketPlace::Tp_Shopee, $produto->getSku(), $mktImageId, $value->getIdFutura());
                        } else {
                            $this->dmodel_marketplace_marketplace->saveMarketplaceProductImageFkImage(Type_MarketPlace::Tp_Shopee, $value->getId(), $mktImageId, $value->getIdFutura());
                        }
                    } else {
                        throw new exception($this->error);
                    }
                } else {
                    $image_list[] = $value->getImageMktId();
                }
            }
        }

        $descriptionLimit = (($this->config->get('shopee_environment') == Type_Environment::Tp_Production) ? 4800 : 450);
        $brand = array_search(Type_ShopeeAttribute::Tp_Marca, array_column($attributes, 'attribute_name'));
        $brandValueId = $brand !== false ? $attributes[$brand]['value_id'] : 0;
        $brandName = $brand !== false ? $attributes[$brand]['value_name'] : 'NoBrand';

        $brand = [
            'brand_id' => (integer)$brandValueId,
            'original_brand_name' => $brandName,
        ];

        $dimension = [
            'package_width' => (integer)$produto->getWidth(),
            'package_length' => (integer)$produto->getLength(),
            'package_height' => (integer)$produto->getHeight(),
        ];

        $jsonSend = array(
            'original_price' => $pricePer,
            'item_name' => $title,
            'description' => empty($description) ? ' ' : substr($description, 0, $descriptionLimit),
            'normal_stock' => $produto->getQuantity() < 0 ? 0 : (integer)$produto->getQuantity(),
            'weight' => floatval($produto->getWeight()),
            'item_sku' => $produto->getSku(),
            'item_status' => $produto->getStatus() == TypeProduct_Status::Tp_Habilitado ? 'NORMAL' : 'UNLIST',
            'condition' => $produto->getParam('condition'),

            'brand' => $brand,
            'dimension' => $dimension,

            'category_id' => (integer)$category_id,
            'attribute_list' => $attribute_list,
            'logistic_info' => $logistic_list,
            'image' => [
                'image_id_list' => $image_list
            ]
        );

        if (!$produto->hasVariations()) {
            // Produto Normal
            if ($produto->getMktId() != null) {

                if (empty($logistic_list)) {
                    unset($jsonSend['logistic_info']);
                }

                if (!$this->updateProductStock($produto->getMktId(), $produto->getQuantity())) {
                    throw new exception($this->error);
                }

                if (!$this->updateProductPrice($produto->getMktId(), $pricePer)) {
                    throw new exception($this->error);
                }

                $retorno = $this->updateProduct($produto->getMktId(), $jsonSend);
            } else {
                $retorno = $this->addProduct($jsonSend);
                $addedProduct = true;
            }
        } else {
            // Grade
            $variacoes = $produto->getVariacao();

            if ($produto->getMktId() != null) {
                $retorno = $this->updateProduct($produto->getMktId(), $jsonSend);
            } else {
                $retorno = $this->addProduct($jsonSend);
                $addedProduct = true;
            }

            if (!$retorno){
                throw new exception($this->error);
            }

            $variationAttributes = [];
            $model = [];
            $tier_variation = [];
            foreach ($variacoes as $key => $variacao){
                $tier_index = [];
                if ($variacao->getStatus() == Type_Status::Tp_Desabilitado){
                    continue;
                }
                $this->getVariationOptions($variacao, $variationAttributes, 'color', $variacao->getTemplateCor(), $variacao->getCor());
                $this->getVariationOptions($variacao, $variationAttributes, 'size', $variacao->getTemplateTamanho(), $variacao->getTamanho());
                $this->getVariationOptions($variacao, $variationAttributes, 'specification', $variacao->getTemplateEspecificacao(), $variacao->getEspecificacao());

                $keysVariation = array_keys($variationAttributes);

                foreach ($keysVariation as $value){
                    switch ($value){
                        case 'color':
                            $variationValue = $variacao->getCor();
                            break;
                        case 'size':
                            $variationValue = $variacao->getTamanho();
                            break;
                        case 'specification':
                            $variationValue = $variacao->getEspecificacao();
                            break;
                    }
                    $tier_index[] = array_search($variationValue, array_column($variationAttributes[$value]['options'], 'value'));
                }

                $model[] = [
                    'tier_index' => $tier_index,
                    'normal_stock' => (integer)$variacao->getQuantity(),
                    'original_price' => $variacao->getValor(),
                    'model_sku' => $variacao->getSku(),
                ];
            }

            foreach ($variationAttributes as $key => $value){
                $option_list = [];
                foreach ($value['options'] as $option_item) {
                    $option = [
                        'option' => $option_item['value']
                    ];

                    // se for o primeiro tier enviar as imagens da variação
                    if (($key == array_keys($variationAttributes)[0])
                        && (count(array_column($variationAttributes[$key]['options'], 'image')) > 0)
                        && (count($variationAttributes[$key]['options']) == count(array_column($variationAttributes[$key]['options'], 'image')))){
                        $option['image'] = ['image_id' => $option_item['image']];
                    }

                    $option_list[] = $option;
                }

                $tier_variation_item = [
                    'name' => $value['name'],
                    'option_list' => $option_list,
                ];
                $tier_variation[] = $tier_variation_item;
            }

            $tiersJsonSend = array(
                'item_id' => $retorno->item_id,
                'tier_variation' => $tier_variation,
                'model' => $model,
            );

            if ($produto->getMktId() != null) {
                $retornoVariation = $this->getProductVariations($retorno->item_id);
                $tierVariationStructureDiff = count($retornoVariation->tier_variation) != count($variationAttributes);

                // Se a estrutura que está na Shopee estiver diferente da grade do sistema, tem que refazer a Tier Variation
                if ($tierVariationStructureDiff){
                    $retornoVariation = $this->addTierVariation($tiersJsonSend);
                } else {
                    // Se for só variações faltando, tem que atualizar o tier variation e adicionar os modelos faltantes
                    // AQUI SERÁ INICIADA UMA ÉPICA GAMBIARRA PRA ATUALIZAR AS GRADES NA SHOPEE QUANDO ADICIONA VARIAÇÕES, PORQUE NO MOMENTO É ASSIM QUE FUNCIONA NA API DELES!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    // Não apagar os models, nem remover options do tier variation
                    $variationsOptionsList = [];
                    foreach ($retornoVariation->tier_variation as $value) {
                        $optionsList = [];
                        foreach ($value->option_list as $option) {
                            $optionsList[] = $option->option;
                        }

                        $variationsOptionsList[] = [
                            'name' => $value->name,
                            'oldOptionList' => $optionsList,
                        ];
                    }

                    // UPDATE TIER VARIATION
                    $new_tier_variation = [];
                    $new_tier_variation_options_list = [];
                    foreach ($variationAttributes as $key => $value) {
                        $option_list = [];
                        $old_tier_variation = $variationsOptionsList[array_search($value['name'], array_column($tier_variation, 'name'))]['oldOptionList'];
                        $new_tier_variation_options = array_unique(array_merge($old_tier_variation, array_column($value['options'], 'value')));
                        $new_tier_variation_options_list[$key] = $new_tier_variation_options;
                        foreach ($new_tier_variation_options as $option_item) {
                            $option = [
                                'option' => $option_item
                            ];

                            // se for o primeiro tier enviar as imagens da variação
                            if (($key == array_keys($variationAttributes)[0])
                                && (count(array_column($variationAttributes[$key]['options'], 'image')) > 0)
                                && (count($variationAttributes[$key]['options']) == count(array_column($variationAttributes[$key]['options'], 'image')))){
                                $option['image'] = ['image_id' => $value['options'][array_search($option_item, array_column($value['options'], 'value'))]['image']];
                            }

                            $option_list[] = $option;
                        }

                        $new_tier_variation_item = [
                            'name' => $value['name'],
                            'option_list' => $option_list,
                        ];
                        $new_tier_variation[] = $new_tier_variation_item;
                    }

                    $updateTierJsonSend = array(
                        'item_id' => $retorno->item_id,
                        'tier_variation' => $new_tier_variation,
                    );
                    $updateTierVariation = $this->updateTierVariation($updateTierJsonSend);
                    // FIM TIER VARIATION


                    $modelsAdd = [];
                    $keysVariation = array_keys($variationAttributes);
                    foreach ($variacoes as $variacao) {
                        if (is_null($variacao->getMktVariation_id()) && ($variacao->getStatus() == TypeProduct_Status::Tp_Habilitado)) {
                            $tier_index = [];
                            foreach ($keysVariation as $value) {
                                switch ($value) {
                                    case 'color':
                                        $variationValue = $variacao->getCor();
                                        break;
                                    case 'size':
                                        $variationValue = $variacao->getTamanho();
                                        break;
                                    case 'specification':
                                        $variationValue = $variacao->getEspecificacao();
                                        break;
                                }
                                $tier_index[] = array_search($variationValue, $new_tier_variation_options_list[$value]);
                            }

                            $modelsAdd[] = [
                                'tier_index' => $tier_index,
                                'normal_stock' => (integer)$variacao->getQuantity(),
                                'original_price' => $variacao->getValor(),
                                'model_sku' => $variacao->getSku(),
                            ];
                        }
                    }

                    if (!empty($modelsAdd)) {
                        $modelsJsonSend = array(
                            'item_id' => $retorno->item_id,
                            'model_list' => $modelsAdd,
                        );

                        $retornoModels = $this->addProductModel($modelsJsonSend);
                    }

                    if ($retornoVariation) {
                        $retornoVariation = $this->getProductVariations($retorno->item_id);
                    }
                    // FIM DA GAMBIARRA
                }
            } else {
                $retornoVariation = $this->addTierVariation($tiersJsonSend);
            }


            if ((isset($retornoVariation)) && ($this->getPropery($retornoVariation, 'model')) && (count($retornoVariation->model) > 0)) {
                foreach ($retornoVariation->model as $key => $variationShopee) {
                    $variation = $produto->getVaricaoProductId($variationShopee->model_sku);
                    if ($variation) {
                        $variation->setMktVariation_id($variationShopee->model_id);
                    }
                }
            }

            if ($produto->getMktId() != null) {
                if (!$this->updateProductStock($produto->getMktId(), $produto->getQuantity(), $produto->getVariacao())) {
                    throw new exception($this->error);
                }

                if (!$this->updateProductPrice($produto->getMktId(), $pricePer, $produto->getVariacao())) {
                    throw new exception($this->error);
                }
            }
        }

        if ($retorno) {
            if ($addedProduct){
                $produto->setMktRetorno($this->mountProductMktRetorno($retorno));
            } else {
                $produto->setMktRetorno($this->getProduto($retorno->item_id));
            }
            return $produto;
        } else {
            throw new exception($this->error);
        }
    }

    public function getOrder($mktOrderId)
    {
        $order = $this->getOrderMarketplace($mktOrderId);

        if (!$order instanceOf StdClass) {
            return false;
        } else {
            return $this->orderJsonToObject($order);
        }
    }

    public function setEnviarNFEData($mktOrderId, $data)
    {
        $data_emissao = strtotime($data['data_hora_emissao']);

        $datasend = [
            'order_sn' => $mktOrderId,
            'invoice_data' => [
                'number' => str_pad($data['numero_nfe'], 9, 0, STR_PAD_LEFT),
                'series_number' => str_pad($data['serie'], 3, 0, STR_PAD_LEFT),
                'access_key' => $data['chave_acesso'],
                'issue_date' => $data_emissao,
                'total_value' => (float)$data['total'],
                'products_total_value' => (float)$data['total_produtos'],
                'tax_code' => str_pad($data['cfop'], 4, 0, STR_PAD_LEFT),
            ],
        ];

        return $this->addInvoiceData($mktOrderId, $datasend);
    }

    public function setPedidoEnvio($mktOrderId, $data)
    {
        $datasend = [
            'order_sn' => $mktOrderId,
            'dropoff' => [
//                'number' => $data['numero_nfe'],
            ],
        ];

        return $this->shipOrder($mktOrderId, $datasend);
    }

    public function setDesincronizarProduto($marketId, $id)
    {
        $delete = $this->delete($marketId);

        if (!$delete) {
            throw new exception($this->error);
        } else {
            return true;
        }
    }

    public function pauseProduct($itemId)
    {
        $datasend = [
            'item_status' => Type_ShopeeStatus::Tp_Unlist
        ];
        $result = $this->updateProduct($itemId, $datasend);

        if (!$result) {
            throw new exception($this->error);
        } else {
            return true;
        }
    }

    public function getSearchOrderShopee($data = array()){
        $param = array();

        $filterById = isset($data['filter_id']) && ($data['filter_id']);

        if ($filterById) {
            $param = $data['filter_id'];

            $orders = $this->getOrder($param);
        } else {
            $param['time_range_field'] = 'create_time';

            if (!empty($data['filter_date_start'])) {
                $param['time_from'] = (integer)strtotime($data['filter_date_start'] . 'T00:00:00.000-00:00GMT-0300');
            }

            if (!empty($data['filter_date_end'])) {
                $param['time_to'] = (integer)strtotime($data['filter_date_end'] . 'T23:59:59.000-00:00GMT-0300');
            }

            if (isset($data['filter_status']) && $data['filter_status']) {
                $param['order_status'] = $data['filter_status'];
            }

            if (isset($data['offset']) && $data['offset'] > 0) {
                $param['cursor'] = (string)$data['offset'];
            }

            if (isset($data['limit'])) {
                $param['page_size'] = (integer)$data['limit'];
            }

            $orders = $this->getOrderList($param);
        }

        if ($this->error) {
            if (strpos($this->error, 'order is not found') > 0){
                return ['error' => 'Pedido não encontrado'];
            } else {
                return ['error' => $this->error];
            }

        } else {
            if ($filterById){
                return array(
                    'results' => [0 => (object)["order_sn" => ($orders->getMktId())]],
                    'more' => false,
                    'next_cursor' => "",
                    'paging-total' => 1
                );
            } else {
                return array(
                    'results' => $orders->order_list,
                    'more' => $orders->more,
                    'next_cursor' => $orders->next_cursor,
                    'paging-total' => count($orders->order_list)
                );
            }
        }

    }
}
