<?php

$loader = $this->registry->get('load');
$loader->dmodel('marketplace/mktpedido');

final class DModelShopeeShopeepedido extends DModelmarketplacemktpedido
{
    //Funcao usada para sincronizar automaticamente os pedidos que estao na Shopee
    public function processOrder($tempoLimite = false)
    {
        $this->load->dmodel('marketplace/mktpedido');
        $this->load->dmodel('marketplace/marketplace');

        $retorno = array("fail_order" => 0);

        // Processa a fila interna
        $this->db->query("DELETE FROM `" . DB_PREFIX . "marketplace_api_call` WHERE tipo_integracao = " . Type_MarketPlace::Tp_Shopee . " AND done = 1");
        $ordersQueue = $this->db->query("SELECT * FROM `" . DB_PREFIX . "marketplace_api_call` WHERE tipo_integracao = " . Type_MarketPlace::Tp_Shopee . " AND callType='order' and `done` = '0' limit 100 ")->rows;

        if ($ordersQueue) {
            $ordersQueueGroup = array_chunk($ordersQueue, 50);
            foreach ($ordersQueueGroup as $key => $chunkOrdersQueue) {
                foreach ($chunkOrdersQueue as $mktOrder) {
                    $orderId = $mktOrder['callId'];

                    $order = $this->shopee->getOrder($orderId);
                    if (!$order) {
                        continue;
                    }

                    $this->saveOrder($order, $retorno);
                }
                if (($tempoLimite) && (new DateTime($this->db->dataAtual()) > $tempoLimite)) {
                    break;
                }
            }
        }

        // Processa a fila de marketplace da Shopee
        $shop_id = $this->config->get('shopee_shop_id');
        if (!empty($shop_id)){
            $order = $this->ecommerceapi->getMarketplaceQueue(Type_MarketPlace::Tp_Shopee, $shop_id, Type_CallApi::Tp_Order);

            if (!empty($order->data)){
                foreach ($order->data as $item){
                    $apiCallAdded = $this->dmodel_marketplace_marketplace->addAPICall(Type_MarketPlace::Tp_Shopee, $item->entity_id, Type_CallApi::Tp_Order);
                    if ($apiCallAdded){
                        $this->ecommerceapi->deleteMarketplaceQueue(Type_MarketPlace::Tp_Shopee, $shop_id, Type_CallApi::Tp_Order, $item->entity_id);

                        $orderData = $this->shopee->getOrder($item->entity_id);
                        if (!$orderData) {
                            continue;
                        }
                        $this->saveOrder($orderData, $retorno);
                    } else {
                        $this->write->log('Erro ao adicionar pedido da Shopee na API call, ID do pedido: ' . $item->entity_id);
                    }

                    if (($tempoLimite) && (new DateTime($this->db->dataAtual()) > $tempoLimite)) {
                        break;
                    }
                }
            }
        }

        return $retorno;
    }

    public function saveOrder($order, &$retorno)
    {
        try {
            $this->saveMarketplaceLog();
            $this->db->startTransaction();

            $order_info = $this->getMktOrder($order->getMktId(), Type_MarketPlace::Tp_Shopee);

            // TESTE
            //$this->updateOrderShopee($order_info, $order);

            if ($order_info) {
                $lastStatus = $this->dmodel_marketplace_mktpedido->getLastMktOrderStatus($order_info['order_id']);
                switch ($order->getParam('status')) {
                    case Type_ShopeeOrderApiStatus::Tp_Shipped:
                        if ($lastStatus['mktStatus'] != $order->getParam('status')) {
                            $tracking = $this->shopee->getTrackingNumber($order->getMktId());
                            $this->addShopeeTracking($order, $order_info['order_id'], $tracking);
                        }
                        break;
                }

                if ($lastStatus['mktStatus'] != $order->getParam('status')) {
                    $this->updateOrderShopee($order_info, $order);
                }
            } else {
                $order_info = [];
                if ($order->getParam('status') <> Type_ShopeeOrderApiStatus::Tp_Unpaid) {
                    /* Quando o pedido já teve o status alterado de inicio, por exemplo, cliente pagou com cartão e já foi aprovado no momento da sincronia
                    o status que vêm do shopee já é o status final, por isso eu forço aqui na inserção à vir com o primeiro status e depois
                    quando ele entrar na atualização, ira lançar os demais status.
                    Ps. nessa situação haverá dois registros na queue com o mesmo status(tanto o novo quanto o pago, estarao como pago),
                    Ficando o primeido do add como UNPAID, e o segundo como READY_TO_SHIP */
                    $data = ['status' => Type_ShopeeOrderApiStatus::Tp_Unpaid];
                    $order_id = $this->insertShopeeOrder($order->getMktId(), $data);
                    $order_info['order_id'] = $order_id;
                    $this->updateOrderShopee($order_info, $order);
                } else {
                    $this->insertShopeeOrder($order->getMktId());
                }
            }

            $this->db->query("UPDATE `" . DB_PREFIX . "marketplace_api_call` SET done = '1' WHERE tipo_integracao = " . Type_MarketPlace::Tp_Shopee . " AND callId = '" . $order->getMktId() . "' and callType='" . Type_CallApi::Tp_Order . "';");
            $this->db->commit();

        } catch (Exception $e) {
            $retorno['fail_order']++;
            $this->db->rollback();
        }
    }

    public function updateOrderShopee($orderData, $mktOrderData)
    {
        try {
            $this->load->dmodel('account/customer');
            $orderAddress = $this->getOrderAddress($mktOrderData);
            $customerInfo = $this->getOrderCustomer($mktOrderData, $orderAddress);
            $customerAddress = $this->dmodel_account_customer->getAddress($customerInfo['customer_id']);

            $customerData = [
                'firstname' => $mktOrderData->getBuyer()->getFirstName(),
                'lastname' => $mktOrderData->getBuyer()->getLastName(),
            ];

            if (strpos($customerInfo['firstname'], '*') !== false) {
                $this->dmodel_account_customer->updateOCCustomerName($customerInfo['customer_id'], $customerData);

                // Atualiza pedido
                $this->updateOrderCustomerName($orderData, $mktOrderData);
            }

            if (strpos($customerAddress['logradouro'], '*') !== false || $customerAddress['numero'] == 0) {

                $this->dmodel_account_customer->updateOCCustomerAddressMktPlace($customerInfo['address_id'], $orderAddress['billing'], $customerData);

                // Atualiza pedido
                $this->updateOrderAddress($orderData, $mktOrderData);
            }

            $this->updateOrderStatusShopee($orderData['order_id'], $mktOrderData->getParam('status'), $mktOrderData->getParam('status'));
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    public function updateOrderStatusShopee($order_id, $mktStatus, $mktStatusType)
    {
        try {
            // Status
            $status_id = $this->getShopeeStatus($mktStatus);
            $order_history_id = $this->updateOrderHistory($order_id, $status_id, '');
            $dataStatus = array(
                "order_id" => $order_id,
                "order_history_id" => $order_history_id,
                "mktStatus" => $mktStatusType,
                "tipo_origem" => Type_NotificacaoOrigem::Tp_Recebimento,
                "tipo_situacao" => Type_NotificacaoStatus::Tp_SituacaoRecebido,
                "msg_erro" => ''
            );
            $this->addMktOrderStatus($dataStatus);

        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    public function getShopeeStatus($order_status)
    {
        switch ($order_status) {
            case Type_ShopeeOrderApiStatus::Tp_Unpaid:
                return $this->config->get('shopee_order_status_unpaid');
            case Type_ShopeeOrderApiStatus::Tp_PendingInvoice:
                return $this->config->get('shopee_order_status_pending_invoice');
            case Type_ShopeeOrderApiStatus::Tp_ReadyToShip:
                return $this->config->get('shopee_order_status_ready_to_ship');
            case Type_ShopeeOrderApiStatus::Tp_Processed:
                return $this->config->get('shopee_order_status_processed');
            case Type_ShopeeOrderApiStatus::Tp_RetryShip:
                return $this->config->get('shopee_order_status_retry_ship');
            case Type_ShopeeOrderApiStatus::Tp_Shipped:
                return $this->config->get('shopee_order_status_shipped');
            case Type_ShopeeOrderApiStatus::Tp_ToConfirmReceive:
                return $this->config->get('shopee_order_status_to_confirm_receive');
            case Type_ShopeeOrderApiStatus::Tp_InCancel:
                return $this->config->get('shopee_order_status_in_cancel');
            case Type_ShopeeOrderApiStatus::Tp_Cancelled:
                return $this->config->get('shopee_order_status_cancelled');
            case Type_ShopeeOrderApiStatus::Tp_ToReturn:
                return $this->config->get('shopee_order_status_to_return');
            case Type_ShopeeOrderApiStatus::Tp_Completed:
                return $this->config->get('shopee_order_status_completed');
            default:
                $this->log->write("Desenvolvedor: tipo " . $order_status . " não adicionado. Função: getShopeeStatus");
        }
    }

    public function updateNfeEnviadoShopee($order_id)
    {
        $sql = ' update oc_order_nfe set shopee_nf_enviado = ' . Type_Enviado::Tp_Enviado . ' where order_id = ?';

        $this->db->executeSql($sql, [$order_id]);
    }

    public function insertShopeeOrder($shopeeOrderId, $data = [], $syncManual = false)
    {
        $this->load->type('tipocomum');
        $this->load->type('tipomarketplace');
        $this->load->helper('ftr_geral');
        $this->load->dmodel('checkout/order');
        $this->load->dmodel('shopee/shopeeproduto');

        $pedido = $this->marketplace->getOrder(Type_MarketPlace::Tp_Shopee, $shopeeOrderId);

        //Caso retorne false na função, é porque não encontrou pedido...
        if (!$pedido) {
            return true;
        }

        $this->load->dmodel('marketplace/mktproduto');
        $this->load->dmodel('marketplace/mktprodutoshopee');
        $this->load->dmodel('catalog/product');

        $adFieldsOrder = array();
        $adFieldsOrderValue = array();
        $adjustmentKit = false;
        $mkt_comission_total = 0;

        $status = $data['status'] ?? $pedido->getParam('status');

        $this->db->startTransaction();
        try {
            $dadosProd = array();
            $order_payment = $this->shopee->getPaymentDetails($shopeeOrderId);
            if ($this->config->get('shopee_comission_status')) {
                $mkt_comission_total = $order_payment->order_income->commission_fee;
            }
            foreach ($pedido->getItens() as $product) {
                $oc_mktproduct = $this->dmodel_marketplace_mktproduto->getMarketPlaceFromMarketId($product->getMktId(), Type_MarketPlace::Tp_Shopee);

                $product_id = 0;
                $variation_id = '';
                $productDB = null;

                if ($oc_mktproduct && $oc_mktproduct['tipo_produto'] == Type_ProdutoMkt::Tp_MktProd_Grade) {
                    //é vinculado com produto grade!! verificando então qual é a variação correta que está ligada ao produto...
                    if ($product->getMktVariationId()) {
                        $variation_id = $product->getMktVariationId();
                        $productItemGrid = $this->dmodel_marketplace_mktproduto->getProductFromVariation($variation_id, Type_MarketPlace::Tp_Shopee);

                        if (isset($productItemGrid['product_id'])) {
                            $product_id = $productItemGrid['product_id'];
                        }
                    }
                } elseif ($oc_mktproduct && ($oc_mktproduct['tipo_produto'] == Type_ProdutoMkt::Tp_MktProd_Normal) && isset($oc_mktproduct['product_key_id'])) {
                    $productDB = $this->dmodel_marketplace_mktprodutoshopee->getProduct($oc_mktproduct['product_key_id']);
                    if ($productDB) {
                        $product_id = $productDB['product_id'];
                    }
                }

                if ((is_null($productDB)) && ($product_id != 0)) {
                    $productDB = $this->dmodel_marketplace_mktprodutoshopee->getProduct($product_id);
                }

                if (!$productDB) {
                    $dadosProd[] = array(
                        'product_id' => $product_id,
                        'name' => $product->getProductName(),
                        'model' => '',
                        'quantity' => $product->getQuantity(),
                        'price' => $product->getPrice(),
                        'total' => $product->getQuantity() * $product->getPrice(),
                        'marketId' => $product->getMktId(),
                        'mkt_comission' => 0,
                        'mkt_variation_id' => $variation_id,
                        'mktOrderId' => $product->getMktIdOrderItem()
                    );
                } else {
                    $dadosProd[] = array(
                        'product_id' => $product_id,
                        'name' => $productDB['name'],
                        'model' => $productDB['model'],
                        'quantity' => $product->getQuantity(),
                        'price' => $product->getPrice(),
                        'total' => $product->getQuantity() * $product->getPrice(),
                        'marketId' => $product->getMktId(),
                        'mkt_comission' => 0,
                        'mkt_variation_id' => $variation_id,
                        'mktOrderId' => $product->getMktIdOrderItem()
                    );
                }
            }

            $total_data = array();

            $order_id = $this->addOrder($pedido, $mkt_comission_total, Type_ShopeeModule::Tp_Payment, Type_ShopeeModule::Tp_Shipping, $adFieldsOrder, $adFieldsOrderValue, true);

            foreach ($dadosProd as $prod) {
                $order_product_id = $this->addOrderProduct($order_id, $prod);
            }

                $this->addMktOrder(array(
                    'order_id' => (int)$order_id,
                    'mktOrderId' => $pedido->getMktId(),
                    'order_product_id' => null,
                    'tipo_integracao' => Type_MarketPlace::Tp_Shopee,
                    'origem_captura' => $syncManual ? Type_MktOrigemCaptura::Manual : Type_MktOrigemCaptura::Automatica
                ));

            // rateia valor da comissão do pedido pelos itens
            if ($this->config->get('shopee_comission_status')) {
                $this->dmodel_checkout_order->updateApportionment($order_id, $mkt_comission_total, Type_Apportionment::MktCommission, true);
            }

            $this->language->load('total/sub_total');
            $total_data[] = array(
                'code' => 'sub_total',
                'title' => $this->language->get('heading_title'),
                'text' => $this->currency->format($pedido->getSubTotal(), $this->currency->getCode()),
                'value' => (float)$pedido->getSubTotal(),
                'sort_order' => $this->config->get('sub_total_sort_order')
            );

            $shipping_cost = $pedido->getShippingCost();
            $shopee_discount = $pedido->getParam('shopee_discount') ?? 0;
            $total = $pedido->getTotal() - $shopee_discount;
            if ($total <= 0) {
                $this->shopee->setErrorShopee("Shopee Order API valor zerado: " . $shopeeOrderId);
                throw new exception('Valor total zerado');
            }

            $method_title = ($pedido->getShippingName()) ? $pedido->getShippingName() : $this->getModuleName(Type_ShopeeModule::Tp_Shipping, 'shipping');
            if ($shipping_cost < $order_payment->order_income->estimated_shipping_fee) {
                if ($shipping_cost == 0) {
                    $method_title = $method_title . ' (Cupom Frete Grátis)';
                } else {
                    $method_title = $method_title . ' (Cupom Frete)';
                }
            }

            if (!$pedido->getAddressCombinar()) {
                $total_data[] = array(
                    'code' => 'shipping',
                    'title' => ($method_title) ? $method_title : $pedido->getShippingName(),
                    'text' => $this->currency->format((float)$shipping_cost, $this->currency->getCode()),
                    'value' => (float)$shipping_cost,
                    'sort_order' => $this->config->get('shipping_sort_order')
                );
            }

            $this->language->load('total/total');
            $total_data[] = array(
                'code' => 'total',
                'title' => $this->language->get('heading_title'),
                'text' => $this->currency->format((float)$total, $this->currency->getCode()),
                'value' => (float)$total,
                'sort_order' => $this->config->get('total_sort_order')
            );

            $orderModule = 0;
            if ($pedido->getDiscount() > 0) {
                $total_data[] = array(
                    'code' => 'descontoseller',
                    'title' => 'Descontos do Vendedor',
                    'text' => $this->currency->format($pedido->getDiscount() * -1),
                    'value' => $pedido->getDiscount() * -1,
                    'sort_order' => $this->config->get('sub_total_sort_order') + 1
                );
                $orderModule = $this->config->get('sub_total_sort_order') + 1;
            }

            if ($shopee_discount > 0) {
                $total_data[] = array(
                    'code' => 'descontoshopee',
                    'title' => 'Descontos da Shopee',
                    'text' => $this->currency->format($pedido->getParam('shopee_discount') * -1),
                    'value' => $pedido->getParam('shopee_discount') * -1,
                    'sort_order' => $orderModule + 1
                );
                $orderModule += 1;
            }

            $this->dmodel_checkout_order->updateApportionmentAll($order_id,
                array(
                    Type_Apportionment::Shipping => $shipping_cost,
                    Type_Apportionment::Discount => $pedido->getDiscount(),
                    Type_Apportionment::Increase => $pedido->getAcres()
                )
            );

            $this->addOrderTotal($order_id, $total_data);

            $commentHistory = "Shopee (Venda #" . $shopeeOrderId . ")";
            $order_status_id = $this->getShopeeStatus($status);

            $order_history_id = $this->updateOrderHistory($order_id, $order_status_id, $commentHistory);

            if ($order_history_id) {
                $data = array(
                    "order_id" => $order_id,
                    "order_history_id" => $order_history_id,
                    "mktStatus" => $status,
                    "tipo_origem" => Type_NotificacaoOrigem::Tp_Recebimento,
                    "tipo_situacao" => Type_NotificacaoStatus::Tp_SituacaoRecebido,
                );
                $this->addMktOrderStatus($data);
            }

            $this->saveMarketplaceLog();

            $this->db->commit();
            return $order_id;
        } catch (Exception $e) {
            $this->db->rollback();
            throw new Exception($e->getMessage());
        }

    }

    public function sendStatus($order_id, $order_status_id, $order_history_id, $reenvio = false)
    {
        $this->load->dmodel('shopee/shopeesetting');
        $this->load->dmodel('checkout/order');
        $this->load->dmodel('notafiscal/notafiscal');
        $this->load->dmodel('wsceo/pedido/wsnotafiscal');

        $key = $this->dmodel_shopee_shopeesetting->getKeyFromOrderStatus($order_status_id);

        if (!$key) {
            return true;//Se não tiver configuração para esse status no shopee, então sai fora, não tem nada a ser feito...
        }

        $key = substr($key['key'], 20, strlen($key['key']) + 20);
        $order = $this->dmodel_checkout_order->getOrder($order_id);
        $order_item = $this->dmodel_checkout_order->getOrderItems($order_id);

        switch ($key) {
            case 'nfe':
                if ($this->existsMktOrderStatus($order_id, Type_ShopeeOrderApiStatus::Tp_ReadyToShip, Type_NotificacaoOrigem::Tp_Recebimento)){
                    return true;
                }

                if ($order['chave_acesso'] == null || trim($order['chave_acesso']) == '') {
                    return false;
                }

                $retorno = $this->sendInvoiceData($order_id, $order, $order_item);

                $status_type = Type_ShopeeOrderApiStatus::Tp_ReadyToShip;
                break;

            // na shopee vai para processado quando o vendedor adicionar informações de envio, sim, eles vêem o mundo de outra forma
            // só da pra testar em produção, então vai ficar comentado e depois será feito em produção
//            case 'processed':
//                $retorno = $this->setOrderShipped($order_id, $order, $order_item);
//                $status_type = Type_ShopeeOrderApiStatus::Tp_Processed;
//                break;


            // fazer depois
//            case 'canceled':
//                $retorno = $this->setCancelOrder($order['mktOrderId']);
//                $status_type = Type_ShopeeOrderApiStatus::Tp_Cancelled;
//                break;

            default :
                return true; //Para não tentar enviar status que são apenas recebidos ou status que não são do shopee
        }

        $this->saveMarketplaceLog();

        if (isset($retorno['erro']) && !empty($retorno['erro'])) {
            $mensagemErro = $retorno['erro'];
            $tipoSituacao = Type_NotificacaoStatus::Tp_SituacaoErro;
        } else {
            $tipoSituacao =  Type_NotificacaoStatus::Tp_SituacaoNotificado;
            $mensagemErro = '';
        }

        $dataStatus = array(
            "order_id" => $order_id,
            "order_history_id" => $order_history_id,
            "mktStatus" => $status_type,
            "tipo_origem" => Type_NotificacaoOrigem::Tp_Envio,
            "tipo_situacao" => $tipoSituacao,
            "msg_erro" => $mensagemErro
        );

        if ($reenvio) {
            $this->updateMktOrderStatus($dataStatus);
        } else if (!$this->dmodel_marketplace_mktpedido->isVinculedMktOrderStatus($order_history_id)) {
            $this->addMktOrderStatus($dataStatus);
        }

        return true;
    }

    private function setOrderShipped($order_id, $order, $order_item)
    {
//        $shippingParameter = $this->shopee->getShippingParameter($order['mktOrderId']);

        // em produção, quando descobrir os campos que precisa, passar aqui
        $data = [

        ];

        return $this->marketplace->setPedidoEnvio(Type_MarketPlace::Tp_Shopee, $order['mktOrderId'], $data);
    }

    public function sendInvoiceData($order_id, $order, $order_item){
//        $this->load->type('tipocomum');

        $subtotal =  array_sum(array_column($order_item,'total'));
        $data = [
            'chave_acesso' => $order['chave_acesso'],
            'numero_nfe' => $order['numero_nfe'],
            'serie' => $order['serie'],
            'data_hora_emissao' => $order['data_hora_emissao'],
            'quantidade_volumes' => $order['quantidade_volumes'],
            'cfop' => $order['cfop'],
            'total' => $order['total'],
            'total_produtos' => $subtotal,
        ];

        $retorno = $this->marketplace->setEnviarNFEData(Type_MarketPlace::Tp_Shopee, $order['mktOrderId'], $data);

        if ($retorno['success']){
            $this->updateNfeEnviadoShopee($order_id);
        }
        return $retorno;
    }

    public function addShopeeTracking($order, $order_id, $tracking){
        $this->load->dmodel('tracking/tracking');

        $dataTracking = array(
            'order_id' => $order_id,
            'shipping_code' => $order->getShippingName(),
            'tracking_code' => $tracking->tracking_number,
            'tracking_complete' => Type_Status::Tp_Desabilitado
        );

        $this->dmodel_tracking_tracking->addTrackingEcommerce($dataTracking);

        $dataOrder = array(
            'order_id' => $order_id,
            'tracking_code' => $tracking->tracking_number
        );

        $this->dmodel_tracking_tracking->addTrackingOrderShipping($dataOrder);
    }

}