using BBWY.Common.Extensions;
using BBWY.Common.Models;
using BBWY.Server.Model;
using BBWY.Server.Model.Db;
using BBWY.Server.Model.Dto;
using FreeSql;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Yitter.IdGenerator;

namespace BBWY.Server.Business
{
    public class PurchaseOrderBusiness : BaseBusiness, IDenpendency
    {
        private IEnumerable<PlatformSDKBusiness> platformSDKBusinessList;
        private TaskSchedulerManager taskSchedulerManager;
        private OrderBusiness orderBusiness;
        private MDSBusiness mdsBusiness;
        private VenderBusiness venderBusiness;

        private IDictionary<Enums.Platform, string> deliverySelfDic;

        public PurchaseOrderBusiness(IFreeSql fsql,
                                     NLog.ILogger logger,
                                     IIdGenerator idGenerator,
                                     IEnumerable<PlatformSDKBusiness> platformSDKBusinessList,
                                     TaskSchedulerManager taskSchedulerManager,
                                     OrderBusiness orderBusiness,
                                     MDSBusiness mdsBusiness,
                                     VenderBusiness venderBusiness) : base(fsql, logger, idGenerator)
        {
            this.platformSDKBusinessList = platformSDKBusinessList;
            this.taskSchedulerManager = taskSchedulerManager;
            this.orderBusiness = orderBusiness;
            this.mdsBusiness = mdsBusiness;
            this.venderBusiness = venderBusiness;

            deliverySelfDic = new Dictionary<Enums.Platform, string>()
            {
                {Enums.Platform.京东 , "1274"} //厂家自送
            };
        }

        public void AddPurchaseOrder(AddPurchaseOrderRequest addPurchaseOrderRequest)
        {
            if (string.IsNullOrEmpty(addPurchaseOrderRequest.PurchaseOrderId) ||
                string.IsNullOrEmpty(addPurchaseOrderRequest.SkuId) ||
               string.IsNullOrEmpty(addPurchaseOrderRequest.ProductId))
                throw new BusinessException("缺少采购单必要信息");

            if (fsql.Select<PurchaseOrder>().Where(po => po.SkuId == addPurchaseOrderRequest.SkuId &&
                                                         po.PurchaseOrderId == addPurchaseOrderRequest.PurchaseOrderId &&
                                                         po.StorageType == addPurchaseOrderRequest.StorageType).Any())
                throw new BusinessException("同一个SkuId和同一种仓储类型中不能存在重复的采购单号");

            var purchaseOrder = addPurchaseOrderRequest.Map<PurchaseOrder>();
            purchaseOrder.Id = idGenerator.NewLong();
            purchaseOrder.CreateTime = DateTime.Now;
            fsql.Insert(purchaseOrder).ExecuteAffrows();
        }

        public void EditPurchaseOrder(EditPurchaseOrderRequest editPurchaseOrderRequest)
        {
            fsql.Update<PurchaseOrder>(editPurchaseOrderRequest.Id).Set(po => po.PurchaseQuantity, editPurchaseOrderRequest.PurchaseQuantity)
                                                                   .Set(po => po.RemainingQuantity, editPurchaseOrderRequest.RemainingQuantity)
                                                                   .Set(po => po.SingleSkuAmount, editPurchaseOrderRequest.SingleSkuAmount)
                                                                   .Set(po => po.SingleFreight, editPurchaseOrderRequest.SingleFreight)
                                                                   .Set(po => po.SingleFirstFreight, editPurchaseOrderRequest.SingleFirstFreight)
                                                                   .Set(po => po.SingleOperationAmount, editPurchaseOrderRequest.SingleOperationAmount)
                                                                   .Set(po => po.SingleConsumableAmount, editPurchaseOrderRequest.SingleConsumableAmount)
                                                                   .Set(po => po.SingleStorageAmount, editPurchaseOrderRequest.SingleStorageAmount)
                                                                   .Set(po => po.SingleDeliveryFreight, editPurchaseOrderRequest.SingleDeliveryFreight)
                                                                   .ExecuteAffrows();
        }

        public IList<PurchaseOrderResponse> GetList(QueryPurchaseOrderRequest queryPurchaseOrderRequest)
        {
            return fsql.Select<PurchaseOrder>().Where(po => po.ShopId == queryPurchaseOrderRequest.ShopId &&
                                                            queryPurchaseOrderRequest.SkuIdList.Contains(po.SkuId) &&
                                                            po.StorageType == queryPurchaseOrderRequest.StorageType)
                                               .ToList()
                                               .Map<IList<PurchaseOrderResponse>>();
        }

        public void DeletePurchaseOrder(long id)
        {
            fsql.Delete<PurchaseOrder>(id).ExecuteAffrows();
        }

        public PreviewOrderResponse PreviewPurchaseOrder(PreviewOrderReuqest previewOrderReuqest)
        {
            if (previewOrderReuqest.Platform != Model.Enums.Platform.阿里巴巴)
                throw new NotImplementedException();
            return platformSDKBusinessList.FirstOrDefault(p => p.Platform == previewOrderReuqest.Platform).PreviewOrder(previewOrderReuqest);
        }

        public void FastCreateOrder(CreateOnlinePurchaseOrderRequest createOnlinePurchaseOrderRequest)
        {
            if (createOnlinePurchaseOrderRequest.Platform != Model.Enums.Platform.阿里巴巴)
                throw new NotImplementedException();
            var dbOrder = fsql.Select<Order>(createOnlinePurchaseOrderRequest.OrderId).ToOne();
            if (dbOrder == null)
                throw new BusinessException("订单不存在");
            //if (dbOrder.OrderState != Model.Enums.OrderState.等待采购)
            //    throw new BusinessException("只能为等待采购的订单进行采购");
            var orderSku = fsql.Select<OrderSku>().Where(osku => osku.OrderId == createOnlinePurchaseOrderRequest.OrderId).ToOne();
            if (orderSku == null)
                throw new BusinessException("订单Sku不存在");

            var createOrderResponse = platformSDKBusinessList.FirstOrDefault(p => p.Platform == createOnlinePurchaseOrderRequest.Platform)
                                                             .FastCreateOrder(createOnlinePurchaseOrderRequest);

            IInsert<PurchaseOrder> insertPurchaseOrder = null;
            IInsert<OrderCostDetail> insertOrderCostDetail = null;
            IInsert<OrderCost> insertOrderCost = null;
            IInsert<OrderDropShipping> insertOrderDropShipping = null;

            #region 采购单
            var purchaseOrder = new PurchaseOrder()
            {
                Id = idGenerator.NewLong(),
                CreateTime = DateTime.Now,
                ProductId = orderSku.ProductId,
                SkuId = orderSku.SkuId,
                PurchaseMethod = Model.Enums.PurchaseMethod.线上采购,
                PurchaseOrderId = createOrderResponse.PurchaseOrderId,
                PurchasePlatform = createOnlinePurchaseOrderRequest.Platform,
                PurchaseQuantity = orderSku.ItemTotal.Value,
                RemainingQuantity = 0,
                ShopId = createOnlinePurchaseOrderRequest.ShopId,
                SingleConsumableAmount = 0,
                SingleDeliveryFreight = 0,
                SingleFirstFreight = 0,
                SingleStorageAmount = 0,
                SingleOperationAmount = 0,
                SingleSkuAmount = createOrderResponse.ProductAmount / orderSku.ItemTotal.Value,
                SingleFreight = createOrderResponse.FreightAmount / orderSku.ItemTotal.Value,
                StorageType = Model.Enums.StorageType.代发
            };
            insertPurchaseOrder = fsql.Insert(purchaseOrder);
            #endregion

            #region 成本明细
            var orderCostDetail = new OrderCostDetail()
            {
                Id = idGenerator.NewLong(),
                ConsumableAmount = 0,
                CreateTime = DateTime.Now,
                DeductionQuantity = orderSku.ItemTotal.Value,
                DeliveryExpressFreight = 0,
                FirstFreight = 0,
                OperationAmount = 0,
                OrderId = createOnlinePurchaseOrderRequest.OrderId,
                ProductId = orderSku.ProductId,
                PurchaseFreight = createOrderResponse.FreightAmount,
                PurchaseOrderPKId = purchaseOrder.Id,
                SkuAmount = createOrderResponse.ProductAmount,
                SkuId = orderSku.SkuId,
                StorageAmount = 0,
                UnitCost = purchaseOrder.UnitCost,
                TotalCost = createOrderResponse.TotalAmount //purchaseOrder.UnitCost * orderSku.ItemTotal.Value
            };
            insertOrderCostDetail = fsql.Insert(orderCostDetail);
            #endregion

            #region 订单成本
            var orderCost = new OrderCost()
            {
                OrderId = orderSku.OrderId,
                CreateTime = DateTime.Now,
                DeliveryExpressFreight = 0,
                IsManualEdited = false,
                PlatformCommissionRatio = 0.05M,
                PreferentialAmount = dbOrder.PreferentialAmount,
                SDCommissionAmount = 0,
                PurchaseAmount = createOrderResponse.TotalAmount
            };
            orderCost.PlatformCommissionAmount = dbOrder.OrderSellerPrice * orderCost.PlatformCommissionRatio;
            orderCost.Profit = dbOrder.OrderSellerPrice +
                               dbOrder.FreightPrice -
                               orderCost.PurchaseAmount -
                               orderCost.DeliveryExpressFreight -
                               orderCost.PlatformCommissionAmount;
            insertOrderCost = fsql.Insert(orderCost);
            #endregion

            #region 采购信息
            var orderDropShipping = new OrderDropShipping()
            {
                OrderId = createOnlinePurchaseOrderRequest.OrderId,
                PurchaseAccountId = createOnlinePurchaseOrderRequest.PurchaseAccountId,
                BuyerAccount = createOnlinePurchaseOrderRequest.BuyerAccount,
                SellerAccount = createOnlinePurchaseOrderRequest.SellerAccount,
                CreateTime = DateTime.Now,
                DeliveryFreight = 0,
                PurchaseAmount = createOrderResponse.TotalAmount,
                PurchaseOrderId = createOrderResponse.PurchaseOrderId,
                PurchasePlatform = createOnlinePurchaseOrderRequest.Platform
            };
            insertOrderDropShipping = fsql.Insert(orderDropShipping);
            #endregion

            fsql.Transaction(() =>
            {
                insertPurchaseOrder.ExecuteAffrows();
                insertOrderCostDetail.ExecuteAffrows();
                insertOrderCost.ExecuteAffrows();
                insertOrderDropShipping.ExecuteAffrows();
                fsql.Update<Order>(createOnlinePurchaseOrderRequest.OrderId).SetIf(dbOrder.OrderState == Enums.OrderState.等待采购, o => o.OrderState, Model.Enums.OrderState.待出库)
                                                                            .Set(o => o.StorageType, Model.Enums.StorageType.代发)
                                                                            .ExecuteAffrows();
            });
        }

        public void DeliveryCallbackFrom1688(string jsonStr)
        {
            logger.Info(jsonStr);
            var orderJObject = JObject.Parse(jsonStr);
            var purchaseOrderId = orderJObject["data"].Value<string>("orderId");
            Task.Factory.StartNew(() => DeliveryCallback(purchaseOrderId, Enums.Platform.阿里巴巴), CancellationToken.None, TaskCreationOptions.LongRunning, taskSchedulerManager.PurchaseOrderCallbackTaskScheduler);
        }

        public void DeliveryCallbackFromPDD(object param)
        {
            var orderJObject = JObject.Parse(param.ToString());
            var purchaseOrderId = orderJObject.Value<string>("orderId");
            Task.Factory.StartNew(() => DeliveryCallback(purchaseOrderId, Enums.Platform.拼多多), CancellationToken.None, TaskCreationOptions.LongRunning, taskSchedulerManager.PurchaseOrderCallbackTaskScheduler);
        }

        /// <summary>
        /// 采购平台回调核心流程
        /// </summary>
        /// <param name="purchaseOrderId"></param>
        /// <param name="callbackPlatform"></param>
        private void DeliveryCallback(string purchaseOrderId, Enums.Platform callbackPlatform)
        {
            string currentProgress = string.Empty;
            try
            {
                #region 查询采购单
                currentProgress = "查询采购单";
                var orderDropshipping = fsql.Select<OrderDropShipping>().Where(o => o.PurchaseOrderId == purchaseOrderId).ToOne();
                if (orderDropshipping == null)
                    throw new Exception("未查询到采购单号");
                #endregion

                #region 查询采购账号
                currentProgress = "查询采购账号";
                var purchaseAccount = fsql.Select<PurchaseAccount>().WhereIf(orderDropshipping.PurchaseAccountId != 0, pa => pa.Id == orderDropshipping.PurchaseAccountId)
                                                                    .WhereIf(orderDropshipping.PurchaseAccountId == 0, pa => pa.AccountName == orderDropshipping.BuyerAccount)
                                                                    .Where(pa => pa.PurchasePlatformId == callbackPlatform).ToOne();
                if (purchaseAccount == null)
                    throw new Exception($"未查询到采购账号{orderDropshipping.BuyerAccount}");
                #endregion

                #region 获取采购单的物流信息
                currentProgress = "获取采购单的物流信息";
                var wayBillNoResponse = platformSDKBusinessList.FirstOrDefault(p => p.Platform == callbackPlatform).GetWayBillNoByOrderId(new QueryOrderWayBillNoRequest()
                {
                    AppKey = purchaseAccount.AppKey,
                    AppSecret = purchaseAccount.AppSecret,
                    AppToken = purchaseAccount.AppToken,
                    OrderId = purchaseOrderId,
                    Platform = callbackPlatform
                });
                #endregion

                #region 查询采购账号的归属店铺
                currentProgress = "查询采购账号归属店铺";
                var shop = mdsBusiness.GetShopInfoByShopId(purchaseAccount.ShopId.Value);
                #endregion

                #region 获取目标平台的物流公司列表
                currentProgress = "获取店铺平台物流公司列表";
                var logisticsCompanyList = venderBusiness.GetLogisticsList(new PlatformRequest()
                {
                    AppKey = shop.AppKey,
                    AppSecret = shop.AppSecret,
                    AppToken = shop.AppToken,
                    Platform = shop.Platform
                });
                #endregion

                #region 物流公司翻译
                currentProgress = "将采购单的物流公司翻译为店铺平台的物流公司";
                var logisticsCompanyId = ConvertLogisticsCompanyId(wayBillNoResponse.LogisticsCompanyName, logisticsCompanyList, shop.Platform);
                #endregion

                #region 店铺平台订单出库
                currentProgress = "店铺平台订单出库";
                orderBusiness.OutStock(new OutStockRequest()
                {
                    AppKey = shop.AppKey,
                    AppSecret = shop.AppSecret,
                    AppToken = shop.AppToken,
                    OrderId = orderDropshipping.OrderId,
                    Platform = shop.Platform,
                    WayBillNo = wayBillNoResponse.WayBillNo,
                    LogisticsId = logisticsCompanyId   //物流公司Id
                });
                #endregion
            }
            catch (Exception ex)
            {
                logger.Error(ex, $"回调平台{callbackPlatform},采购单号{purchaseOrderId},执行进度[{currentProgress}]");
            }
        }

        private string ConvertLogisticsCompanyId(string sourceLogisticsCompanyName, IList<LogisticsResponse> targetLogisticsList, Enums.Platform tagetLogisticsPlatform)
        {
            var match = Regex.Match(sourceLogisticsCompanyName, "(中通|圆通|申通|顺丰|韵达|邮政快递包裹|平邮|EMS|德邦|百世|天天|优速)");
            if (match.Success)
            {
                var sname = match.Groups[1].Value;
                var targetLogistics = targetLogisticsList.FirstOrDefault(t => t.Name.Contains(sname));
                if (targetLogistics != null)
                    return targetLogistics.Id;
            }
            return deliverySelfDic[tagetLogisticsPlatform];
        }

    }
}