using BBWY._1688SDK.entity.OrderPreview;
using BBWY.Common.Http;
using BBWY.Common.Models;
using BBWY.Server.Model;
using BBWY.Server.Model.Db;
using BBWY.Server.Model.Dto;
using com.alibaba.openapi.client;
using com.alibaba.openapi.client.policy;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BBWY.Server.Business
{
    public class _1688Business : PlatformSDKBusiness
    {
        public override Enums.Platform Platform => Enums.Platform.阿里巴巴;
        private RestApiService restApiService;
        private _1688TradeTypeCompare _1688TradeTypeCompare;

        public _1688Business(IMemoryCache memoryCache, NLogManager nLogManager, RestApiService restApiService) : base(memoryCache, nLogManager)
        {
            this.restApiService = restApiService;
            _1688TradeTypeCompare = new _1688TradeTypeCompare();
        }

        private SyncAPIClient GetSyncAPIClient(string appKey, string appSecret)
        {
            if (!memoryCache.TryGetValue(appKey, out SyncAPIClient syncAPIClient))
            {
                syncAPIClient = new SyncAPIClient(appKey, appSecret, restApiService);
                memoryCache.Set(appKey, syncAPIClient, expirationTimeSpan);
            }
            return syncAPIClient;
        }

        public override WayBillNoResponse GetWayBillNoByOrderId(QueryOrderWayBillNoRequest queryOrderWayBillNoRequest)
        {
            var client = GetSyncAPIClient(queryOrderWayBillNoRequest.AppKey, queryOrderWayBillNoRequest.AppSecret);
            RequestPolicy reqPolicy = new RequestPolicy();
            reqPolicy.HttpMethod = "POST";
            reqPolicy.NeedAuthorization = false;
            reqPolicy.RequestSendTimestamp = false;
            reqPolicy.UseHttps = false;
            reqPolicy.UseSignture = true;
            reqPolicy.AccessPrivateApi = false;

            Request request = new Request();
            APIId apiId = new APIId();
            apiId.Name = "alibaba.trade.getLogisticsInfos.buyerView";
            apiId.NamespaceValue = "com.alibaba.logistics";
            apiId.Version = 1;
            request.ApiId = apiId;

            var param = new { orderId = queryOrderWayBillNoRequest.OrderId, webSite = "1688", fields = "logisticsCompanyId,logisticsCompanyName,logisticsBillNo" };
            request.RequestEntity = param;
            if (!string.IsNullOrEmpty(queryOrderWayBillNoRequest.AppToken))
                request.AccessToken = queryOrderWayBillNoRequest.AppToken;
            var result = client.NewRequest(request, reqPolicy);
            if (result.Value<bool>("success") != true)
                throw new BusinessException(result.Value<string>("errorMessage")) { Code = 0 };


            nLogManager.Default().Info($"GetWayBillNoByOrderId QueryOrderWayBillNoRequest {JsonConvert.SerializeObject(queryOrderWayBillNoRequest)} Result {result}");

            var firstJToken = result["result"].FirstOrDefault();
            return new WayBillNoResponse()
            {
                LogisticsCompanyId = firstJToken.Value<string>("logisticsCompanyId"),
                LogisticsCompanyName = firstJToken.Value<string>("logisticsCompanyName"),
                WayBillNo = firstJToken.Value<string>("logisticsBillNo")
            };
        }

        public override PreviewOrderResponse PreviewOrder(PreviewOrderReuqest previewOrderReuqest)
        {
            //logger.Info($"PreviewOrder {JsonConvert.SerializeObject(previewOrderReuqest)}");

            var client = GetSyncAPIClient(previewOrderReuqest.AppKey, previewOrderReuqest.AppSecret);
            RequestPolicy reqPolicy = new RequestPolicy();
            reqPolicy.HttpMethod = "POST";
            reqPolicy.NeedAuthorization = false;
            reqPolicy.RequestSendTimestamp = false;
            reqPolicy.UseHttps = false;
            reqPolicy.UseSignture = true;
            reqPolicy.AccessPrivateApi = false;

            Request request = new Request();
            APIId apiId = new APIId();
            apiId.Name = "alibaba.createOrder.preview";
            apiId.NamespaceValue = "com.alibaba.trade";
            apiId.Version = 1;
            request.ApiId = apiId;

            var param = new CreateOrderPreview()
            {
                addressParam = new AddressParam()
                {
                    fullName = previewOrderReuqest.Consignee.ContactName,
                    mobile = previewOrderReuqest.Consignee.Mobile,
                    phone = previewOrderReuqest.Consignee.TelePhone,
                    postCode = "000000",
                    address = previewOrderReuqest.Consignee.Address,
                    provinceText = previewOrderReuqest.Consignee.Province,
                    cityText = previewOrderReuqest.Consignee.City,
                    areaText = previewOrderReuqest.Consignee.County,
                    townText = previewOrderReuqest.Consignee.Town
                },
                cargoParamList = new List<CargoParam>(),
                flow = previewOrderReuqest.PurchaseOrderMode == Enums.PurchaseOrderMode.批发 ? "general" : "saleproxy"
            };
            foreach (var cargo in previewOrderReuqest.CargoParamList)
            {
                param.cargoParamList.Add(new CargoParam()
                {
                    offerId = long.Parse(cargo.ProductId),
                    specId = cargo.SpecId,
                    quantity = cargo.Quantity
                });
            }
            request.RequestEntity = param;
            if (!string.IsNullOrEmpty(previewOrderReuqest.AppToken))
                request.AccessToken = previewOrderReuqest.AppToken;
            JObject result = null;
            try
            {
                result = client.NewRequest(request, reqPolicy);
                if (result.Value<bool>("success") != true)
                    throw new BusinessException(result.Value<string>("errorMsg")) { Code = 0 };
            }
            catch (Exception ex)
            {
                throw new BusinessException(ex.Message);
            }

            nLogManager.Default().Info($"PreviewOrder Request:{JsonConvert.SerializeObject(previewOrderReuqest)} Response:{result}");

            var orderPreviewResuslt = (JArray)result["orderPreviewResuslt"];
            List<JToken> intersectTradeModeList = new List<JToken>();

            foreach (var orderPreviewJToken in orderPreviewResuslt)
            {
                if (orderPreviewJToken["tradeModelList"] == null)
                    throw new BusinessException("当前交易不可通过API下单,请使用1688网页交易 [交易模式列表为空]");
                var tradeModeJArray = ((JArray)orderPreviewJToken["tradeModelList"]).Where(tradeJToken => tradeJToken.Value<bool>("opSupport"));
                if (tradeModeJArray.Count() == 0)
                    throw new BusinessException("当前交易不可通过API下单,请使用1688网页交易 [没有支持开放平台下单的交易模式]");

                if (intersectTradeModeList.Count() == 0)
                    intersectTradeModeList.AddRange(tradeModeJArray);
                else
                    intersectTradeModeList = intersectTradeModeList.Intersect(tradeModeJArray, _1688TradeTypeCompare).ToList();
            }

            if (intersectTradeModeList.Count() == 0)
                throw new BusinessException("当前交易不可通过API下单,请使用1688网页交易 [多个拆单之间没有相同的交易模式]");
            return new PreviewOrderResponse()
            {
                FreightAmount = orderPreviewResuslt.Sum(jt => jt.Value<decimal>("sumCarriage")) / 100M,
                ProductAmount = orderPreviewResuslt.Sum(jt => jt.Value<decimal>("sumPaymentNoCarriage")) / 100M,
                TotalAmount = orderPreviewResuslt.Sum(jt => jt.Value<decimal>("sumPayment")) / 100M,
                OrderTradeType = new OrderTradeTypeResponse()
                {
                    Code = intersectTradeModeList.First().Value<string>("tradeType"),
                    Name = intersectTradeModeList.First().Value<string>("name"),
                }
            };
        }

        public override CreateOnlinePurchaseOrderResponse FastCreateOrder(CreateOnlinePurchaseOrderRequest createOnlinePurchaseOrderRequest)
        {
            var client = GetSyncAPIClient(createOnlinePurchaseOrderRequest.AppKey, createOnlinePurchaseOrderRequest.AppSecret);
            RequestPolicy reqPolicy = new RequestPolicy();
            reqPolicy.HttpMethod = "POST";
            reqPolicy.NeedAuthorization = false;
            reqPolicy.RequestSendTimestamp = false;
            reqPolicy.UseHttps = false;
            reqPolicy.UseSignture = true;
            reqPolicy.AccessPrivateApi = false;

            Request request = new Request();
            APIId apiId = new APIId
            {
                Name = "alibaba.trade.fastCreateOrder",
                NamespaceValue = "com.alibaba.trade",
                Version = 1
            };
            request.ApiId = apiId;

            var param = new
            {
                flow = createOnlinePurchaseOrderRequest.PurchaseOrderMode == Enums.PurchaseOrderMode.批发 ? "general" : "saleproxy",
                message = createOnlinePurchaseOrderRequest.Remark,
                addressParam = new
                {
                    fullName = createOnlinePurchaseOrderRequest.Consignee.ContactName,
                    mobile = createOnlinePurchaseOrderRequest.Consignee.Mobile,
                    phone = createOnlinePurchaseOrderRequest.Consignee.Mobile,
                    cityText = createOnlinePurchaseOrderRequest.Consignee.City,
                    provinceText = createOnlinePurchaseOrderRequest.Consignee.Province,
                    areaText = createOnlinePurchaseOrderRequest.Consignee.County,
                    townText = createOnlinePurchaseOrderRequest.Consignee.Town,
                    address = createOnlinePurchaseOrderRequest.Consignee.Address
                },
                cargoParamList = createOnlinePurchaseOrderRequest.CargoParamList.Select(cargo => new
                {
                    offerId = long.Parse(cargo.ProductId),
                    specId = cargo.SpecId,
                    quantity = cargo.Quantity
                }),
                tradeType = createOnlinePurchaseOrderRequest.TradeMode
            };

            request.RequestEntity = param;
            if (!string.IsNullOrEmpty(createOnlinePurchaseOrderRequest.AppToken))
                request.AccessToken = createOnlinePurchaseOrderRequest.AppToken;
            var result = client.NewRequest(request, reqPolicy);
            if (result.Value<bool>("success") != true)
            {
                var ex = new BusinessException(result.ToString()) { Code = 0 };
                nLogManager.Default().Error(ex, $"下单失败 订单Id{createOnlinePurchaseOrderRequest.OrderId}\r\n请求参数{JsonConvert.SerializeObject(createOnlinePurchaseOrderRequest)}\r\n1688返回{result}");
                throw ex;
            }

            var totalSuccessAmount = result["result"].Value<long>("totalSuccessAmount") / 100M; //采购单总金额,单位分
            var purchaseOrderId = result["result"].Value<string>("orderId"); //采购单号
            var postFee = result["result"].Value<long>("postFee") / 100M;  //采购单运费,单位分
            var purchaseAmount = totalSuccessAmount - postFee;  //采购成本

            var failedOfferJArray = result["failedOfferList"] != null ? (JArray)result["failedOfferList"] : null;
            if (failedOfferJArray != null)
            {
                StringBuilder failOrderStringBuilder = new StringBuilder();
                foreach (var failedOfferJToken in failedOfferJArray)
                    failOrderStringBuilder.AppendLine(failedOfferJToken.ToString());
                var ex = new Exception(failOrderStringBuilder.ToString());
                nLogManager.Default().Error(ex, $"下单部分商品失败 采购单Id{purchaseOrderId} 请求参数{JsonConvert.SerializeObject(createOnlinePurchaseOrderRequest)}");
            }

            return new CreateOnlinePurchaseOrderResponse()
            {
                TotalAmount = totalSuccessAmount,
                ProductAmount = purchaseAmount,
                FreightAmount = postFee,
                PurchaseOrderId = purchaseOrderId,
                FailProductMessageList = failedOfferJArray == null ? null : failedOfferJArray.Select(failedOfferJToken => failedOfferJToken.ToString()).ToList()
            };
        }

        /// <summary>
        /// 获取订单简单信息
        /// </summary>
        /// <param name="getOrderInfoRequest"></param>
        /// <returns></returns>
        public override OnlinePurchaseOrderSimpleResponse GetOrderSimpleInfo(GetOrderInfoRequest getOrderInfoRequest)
        {
            var client = GetSyncAPIClient(getOrderInfoRequest.AppKey, getOrderInfoRequest.AppSecret);
            RequestPolicy reqPolicy = new RequestPolicy();
            reqPolicy.HttpMethod = "POST";
            reqPolicy.NeedAuthorization = false;
            reqPolicy.RequestSendTimestamp = false;
            reqPolicy.UseHttps = false;
            reqPolicy.UseSignture = true;
            reqPolicy.AccessPrivateApi = false;

            Request request = new Request();
            APIId apiId = new APIId
            {
                Name = "alibaba.trade.get.buyerView",
                NamespaceValue = "com.alibaba.trade",
                Version = 1
            };
            request.ApiId = apiId;

            var param = new
            {
                webSite = "1688",
                orderId = getOrderInfoRequest.OrderId,
                includeFields = "baseInfo,productItems"
            };
            request.RequestEntity = param;
            if (!string.IsNullOrEmpty(getOrderInfoRequest.AppToken))
                request.AccessToken = getOrderInfoRequest.AppToken;
            var result = client.NewRequest(request, reqPolicy);
            if (getOrderInfoRequest.SaveResponseLog)
                nLogManager.Default().Info(result.ToString());
            if (result.Value<bool>("success") != true)
                throw new BusinessException(result.Value<string>("errorMessage")) { Code = 0 };


            return new OnlinePurchaseOrderSimpleResponse()
            {
                PurchaseOrderId = getOrderInfoRequest.OrderId,
                FreightAmount = result["result"]["baseInfo"].Value<decimal>("shippingFee"),
                ProductAmount = result["result"]["baseInfo"].Value<decimal>("totalAmount") - result["result"]["baseInfo"].Value<decimal>("shippingFee"),
                TotalAmount = result["result"]["baseInfo"].Value<decimal>("totalAmount"),
                ItemList = result["result"]["productItems"].Select(itemJToken => new OnlinePurchaseOrderSkuSimpleResponse()
                {
                    ProductId = itemJToken.Value<string>("productID"),
                    SkuId = itemJToken.Value<string>("skuID"),
                    SpecId = itemJToken.Value<string>("specId"),
                    ProductAmount = itemJToken.Value<decimal>("itemAmount"),
                    Quantity = itemJToken.Value<decimal>("quantity"),
                    Price = itemJToken.Value<decimal>("price")
                }).ToList()
            };
        }
    }

    public class _1688TradeTypeCompare : IEqualityComparer<JToken>
    {
        public bool Equals(JToken x, JToken y)
        {
            return x.Value<string>("tradeType").Equals(y.Value<string>("tradeType"));
        }

        public int GetHashCode(JToken obj)
        {
            return obj.GetHashCode();
        }
    }
}