using BBWYB.Common.Extensions;
using BBWYB.Common.Log;
using BBWYB.Common.Models;
using BBWYB.Server.Model;
using BBWYB.Server.Model.Db;
using BBWYB.Server.Model.Db.BBWY;
using BBWYB.Server.Model.Dto;
using FreeSql;
using Newtonsoft.Json;
using System.Numerics;
using System.Text.RegularExpressions;
using Yitter.IdGenerator;

namespace BBWYB.Server.Business
{
    public class OptimizationBusiness : BaseBusiness, IDenpendency
    {
        private FreeSqlMultiDBManager fsqlManager;
        private VenderBusiness venderBusiness;
        private TimeLimitRules timeLimitRules;
        private UserBusiness userBusiness;
        private PurchaseSchemeBusiness purchaseSchemeBusiness;

        public OptimizationBusiness(IFreeSql fsql, NLogManager nLogManager, IIdGenerator idGenerator, FreeSqlMultiDBManager fsqlManager, VenderBusiness venderBusiness, TimeLimitRules timeLimitRules, UserBusiness userBusiness, PurchaseSchemeBusiness purchaseSchemeBusiness) : base(fsql, nLogManager, idGenerator)
        {
            this.fsqlManager = fsqlManager;
            this.venderBusiness = venderBusiness;
            this.timeLimitRules = timeLimitRules;
            this.userBusiness = userBusiness;
            this.purchaseSchemeBusiness = purchaseSchemeBusiness;
        }


        public Enums.TriggerOptimizationReason? GetOptimizationReason(SpuTotalSaleInfo s)
        {
            if (s.IsFirstPurchaseCompleted == false)
                return Enums.TriggerOptimizationReason.首次采购;
            if (s.IsFirstPurchaseCompleted == true &&
                s.IsFirstOptimizationCompleted == false)
            {
                if (s.ItemCount - s.FirstPurchaseCompletedItemCount >= 20)
                    return Enums.TriggerOptimizationReason.首次优化;
                if (s.LastOptimizationTime != null &&
                   (DateTime.Now.Date - s.LastOptimizationTime.Value.Date).TotalDays > 30)
                    return Enums.TriggerOptimizationReason.首次优化;
            }
            if (s.IsFirstOptimizationCompleted == true)
            {
                if (s.LastOptimizationItemCount != 0 && s.ItemCount * 1.0 / s.LastOptimizationItemCount >= 2)
                    return Enums.TriggerOptimizationReason.再次优化;

                if (s.LastOptimizationTime != null &&
                   (DateTime.Now.Date - s.LastOptimizationTime.Value.Date).TotalDays > 30)
                    return Enums.TriggerOptimizationReason.再次优化;
            }
            return null;
        }

        /// <summary>
        /// 良库预警
        /// </summary>
        /// <param name="request"></param>
        /// <exception cref="BusinessException"></exception>
        public void LKInventoryAlertNotification(BatchLKInventoryAlertRequest request)
        {
            nLogManager.Default().Info($"LKInventoryAlertNotification {JsonConvert.SerializeObject(request)}");

            #region 确定JDSKU对应的拳探SKU和拳探SPU
            var jdSkuIdList = request.Items.Select(x => x.Sku).Distinct().ToList();

            var jdqtskuList = fsqlManager.BBWYCfsql.Select<PurchaseOrderSku>()
                                                   .Where(ps1 => ps1.ShopId == request.ShopId && jdSkuIdList.Contains(ps1.SkuId))
                                                   .GroupBy(ps1 => ps1.SkuId)
                                                   .WithTempQuery(g => new { MaxId = g.Max(g.Value.Id) })
                                                   .From<PurchaseOrderSku>()
                                                   .InnerJoin((ps1, ps2) => ps1.MaxId == ps2.Id)
                                                   .ToList((ps1, ps2) => ps2);

            var qtSkuIdList = jdqtskuList.Select(x => x.PurchaseSkuIds).Distinct().ToList();

            var productSkuList = fsql.Select<Model.Db.ProductSku>(qtSkuIdList).ToList();
            if (productSkuList.Count() == 0)
                return;

            var shopId = productSkuList.FirstOrDefault()?.ShopId;
            var productIdList = productSkuList.Select(ps => ps.ProductId).Distinct().ToList();
            var productList = fsql.Select<Product>(productIdList).ToList();
            var dbSpuTotalInfoList = fsql.Select<SpuTotalSaleInfo>().Where(spi => productIdList.Contains(spi.ProductId)).ToList();
            #endregion


            //查询已存在未结束的优化任务
            var dbSpuOptimizationTaskList = fsql.Select<SpuOptimizationTask>()
                                                .Where(t => t.ShopId == shopId &&
                                                            t.IsOptimizationCompleted == false &&
                                                            productIdList.Contains(t.ProductId))
                                                .ToList();


            //优化历史
            var dbSpuOptimizationHistoryList = fsql.Select<SpuOptimizationTask>()
                                              .Where(s1 => productIdList.Contains(s1.ProductId) && s1.IsOptimizationCompleted == true)
                                              .GroupBy(s1 => s1.ProductId)
                                              .WithTempQuery(g => new { MaxId = g.Max(g.Value.Id) })
                                              .From<SpuOptimizationTask>()
                                              .InnerJoin((s1, s2) => s1.MaxId == s2.Id)
                                              .ToList((s1, s2) => s2);


            #region DB Operation
            List<SpuOptimizationTask> insertSpuOptimizationTaskList = new List<SpuOptimizationTask>();
            List<SkuOptimizationTask> insertSkuOptimizationTaskList = new List<SkuOptimizationTask>();
            List<SpuOptimizationBargainTeamTask> insertSpuOptimizationBargainTeamTaskList = new List<SpuOptimizationBargainTeamTask>();
            List<SpuOptimizationCompetitiveTenderTask> insertSpuOptimizationCompetitiveTenderTaskList = new List<SpuOptimizationCompetitiveTenderTask>();
            List<TimeLimitTask> insertTimeLimitTaskList = new List<TimeLimitTask>();
            #endregion

            var belongShop = venderBusiness.GetShopList(request.ShopId).FirstOrDefault();
            if (belongShop == null)
                throw new BusinessException("店铺不存在");

            var bargainTeamList = venderBusiness.GetYiJiaGroup(); //获取议价组
            var bargainTeamIdList = bargainTeamList.Select(t => t.Id).ToList();
            var waitToCompetitiveTenderSchemeList = fsql.Select<PurchaseScheme>()
                                                        .Where(ps => bargainTeamIdList.Contains(ps.BelongBargainTeamId) &&
                                                                     productIdList.Contains(ps.ProductId))
                                                        .ToList();  //需要参与竞标采购方案

            foreach (var productId in productIdList)
            {
                #region 验证
                if (dbSpuOptimizationTaskList.Any(s => s.ProductId == productId))  //过滤未结束的spu任务
                    continue;

                var spuTotalInfo = dbSpuTotalInfoList.FirstOrDefault(psi => psi.ProductId == productId); //spu销量
                if (spuTotalInfo == null)
                    continue;

                var reason = GetOptimizationReason(spuTotalInfo);  //过滤不需要优化的spu
                if (reason == null)
                    continue;
                #endregion

                var skuOptimizationHistory = dbSpuOptimizationHistoryList.FirstOrDefault(h => h.ProductId == productId); //优化历史

                #region qtsku - jdsku 关系匹配
                var currentProductSkuList = productSkuList.Where(ps => ps.ProductId == productId &&
                                                                       jdqtskuList.Any(x => x.PurchaseSkuIds == ps.Id)).ToList();
                if (currentProductSkuList.Count() == 0)
                    continue;

                //拳探sku-京东sku下单关系映射表
                var mappingQT_JDSKUDictionary = new Dictionary<string, string>();
                foreach (var ps in currentProductSkuList)
                {
                    var jdsku = jdqtskuList.FirstOrDefault(x => x.PurchaseSkuIds == ps.Id)?.SkuId;
                    if (string.IsNullOrEmpty(jdsku))
                        continue;
                    if (!mappingQT_JDSKUDictionary.ContainsKey(ps.Id))
                        mappingQT_JDSKUDictionary.TryAdd(ps.Id, jdsku);
                }
                var jdskus = mappingQT_JDSKUDictionary.Values.ToList();
                var qtskus = mappingQT_JDSKUDictionary.Keys.ToList();
                #endregion

                #region 读取JDSKU预估金额
                var jdskuRecentCostList = fsqlManager.BBWYCfsql.Select<SkuRecentCost>(jdskus).ToList();
                #endregion

                #region 创建SPU优化任务
                var spuOptimizationTask = new SpuOptimizationTask()
                {
                    Id = idGenerator.NewLong(),
                    BelongShopId = long.Parse(belongShop.ShopId),
                    BelongShopName = belongShop.ShopName,
                    CompletionTime = null,
                    CreateTime = DateTime.Now,
                    IsOptimizationCompleted = false,
                    LastOptimizationTime = null,
                    ProductId = productId,
                    ShopId = shopId,
                    ProductTitle = productList.FirstOrDefault(p => p.Id == productId)?.ProductName,
                    TriggerOptimizationReason = reason,
                    PreSkuCount = jdskus.Count(),
                    PreItemCount = 0,
                    PrePurchaseAmount = 0M
                };
                insertSpuOptimizationTaskList.Add(spuOptimizationTask);
                #endregion

                #region 创建SKU优化任务
                foreach (var sku in mappingQT_JDSKUDictionary.Keys)
                {
                    mappingQT_JDSKUDictionary.TryGetValue(sku, out string jdSkuId);
                    var requestSkuItem = request.Items.FirstOrDefault(x => x.Sku == jdSkuId);
                    if (requestSkuItem == null)
                        continue;

                    var preItemCount = requestSkuItem.PreItemCount;
                    var prePurchaseAmount = 0M;
                    if (!string.IsNullOrEmpty(jdSkuId))
                    {
                        var jdSkuRecentCost = jdskuRecentCostList.FirstOrDefault(x => x.SkuId == jdSkuId);
                        if (jdSkuRecentCost != null)
                        {
                            prePurchaseAmount = (jdSkuRecentCost.SingleSkuAmount ?? 0M +
                                                     jdSkuRecentCost.SingleFirstFreight ?? 0M +
                                                     jdSkuRecentCost.SingleFreight ?? 0M +
                                                     jdSkuRecentCost.SingleDeliveryFreight ?? 0M +
                                                     jdSkuRecentCost.SingleConsumableAmount ?? 0M +
                                                     jdSkuRecentCost.SingleInStorageAmount ?? 0M +
                                                     jdSkuRecentCost.SingleOutStorageAmount ?? 0M +
                                                     jdSkuRecentCost.SinglePackagingLaborAmount ?? 0M +
                                                     jdSkuRecentCost.SingleOperationAmount ?? 0M) * preItemCount;
                        }
                    }
                    var skuOptimizationTask = new SkuOptimizationTask()
                    {
                        Id = idGenerator.NewLong(),
                        CreateTime = DateTime.Now,
                        JDSkuId = jdSkuId,
                        PreItemCount = preItemCount,
                        SkuId = sku,
                        SpuOptimizationTaskId = spuOptimizationTask.Id,
                        PrePurchaseAmount = prePurchaseAmount
                    };
                    insertSkuOptimizationTaskList.Add(skuOptimizationTask);

                    //累计spu优化任务信息
                    spuOptimizationTask.PreItemCount += preItemCount;
                    spuOptimizationTask.PrePurchaseAmount += prePurchaseAmount;
                }
                #endregion

                #region 创建SPU优化议价组任务
                foreach (var department in bargainTeamList)
                {
                    var spuOptimizationBargainTeamTask = new SpuOptimizationBargainTeamTask()
                    {
                        Id = idGenerator.NewLong(),
                        BelongTeamId = department.Id,
                        BelongTeamName = department.DepartmentName,
                        CompletionTime = null,
                        IsOptimizationCompleted = false,
                        SpuOptimizationTaskId = spuOptimizationTask.Id
                    };
                    insertSpuOptimizationBargainTeamTaskList.Add(spuOptimizationBargainTeamTask);

                    #region 创建采购方案竞标任务
                    var waitJoinSchemeList = waitToCompetitiveTenderSchemeList.Where(ps => ps.BelongBargainTeamId == department.Id &&
                                                                                           qtskus.Contains(ps.SkuId))
                                                                              .ToList();
                    if (waitJoinSchemeList.Count() > 0)
                    {
                        insertSpuOptimizationCompetitiveTenderTaskList.AddRange(waitJoinSchemeList.Select(ps => new SpuOptimizationCompetitiveTenderTask()
                        {
                            Id = idGenerator.NewLong(),
                            BargainTeamId = ps.BelongBargainTeamId,
                            CreateTime = DateTime.Now,
                            IsUpdateQuotedPrice = false,
                            SchemeGroupId = ps.SchemeGroupId,
                            SchemeId = ps.Id,
                            SkuId = ps.SkuId,
                            SpuOptimizationBargainTeamTaskId = spuOptimizationBargainTeamTask.Id,
                            SpuOptimizationTaskId = spuOptimizationTask.Id,
                            UpdateTime = DateTime.Now
                        }));
                    }
                    #endregion
                }
                #endregion

                #region 创建优化限时任务

                {
                    //判断sku是否首次采购
                    var isFirst = !dbSpuTotalInfoList.Any(s => s.ProductId == productId);

                    insertTimeLimitTaskList.Add(new TimeLimitTask()
                    {
                        Id = idGenerator.NewLong(),
                        CreateTme = DateTime.Now,
                        //ExpirationTime = DateTime.Now.AddDays(isFirst ? 2 : 1),
                        ExpirationTime = timeLimitRules.CalculateExpirationTime(Enums.TimeLimitTaskType.待议价任务, DateTime.Now.AddDays(isFirst ? 1 : 0)),
                        //OrderId = o.OrderId,
                        //OrderSn = o.OrderSn,
                        ShopId = shopId,
                        //SkuId = waitCheckOrderSku.SkuId,
                        TaskType = Enums.TimeLimitTaskType.待议价任务,
                        TaskId = spuOptimizationTask.Id,
                        Remark = "首次采购限时任务"
                    });
                }
                #endregion

            }


            fsql.Transaction(() =>
            {
                if (insertSpuOptimizationTaskList.Count() > 0)
                    fsql.Insert(insertSpuOptimizationTaskList).ExecuteAffrows();
                if (insertSkuOptimizationTaskList.Count() > 0)
                    fsql.Insert(insertSkuOptimizationTaskList).ExecuteAffrows();
                if (insertSpuOptimizationBargainTeamTaskList.Count() > 0)
                    fsql.Insert(insertSpuOptimizationBargainTeamTaskList).ExecuteAffrows();
                if (insertSpuOptimizationCompetitiveTenderTaskList.Count() > 0)
                    fsql.Insert(insertSpuOptimizationCompetitiveTenderTaskList).ExecuteAffrows();
                if (insertTimeLimitTaskList.Count() > 0)
                    fsql.Insert(insertTimeLimitTaskList).ExecuteAffrows();
            });
        }

        /// <summary>
        /// 更新报价
        /// </summary>
        /// <param name="request"></param>
        /// <param name="userId"></param>
        public void BatchUpdateCompetitiveTenderQuotation(BatchUpdateCompetitiveTenderQuotationRequest request, string userId)
        {
            #region 获取用户和部门信息
            var uInfo = userBusiness.GetisBargainTeamByUserId(userId, true);
            #endregion

            #region 业务验证
            var spuOptimizationTask = fsql.Select<SpuOptimizationTask>(request.SpuOptimizationTaskId).ToOne();
            if (spuOptimizationTask == null)
                throw new BusinessException($"待优化任务{request.SpuOptimizationTaskId}不存在");
            var spuOptimizationBargainTeamTask = fsql.Select<SpuOptimizationBargainTeamTask>().Where(sbt => sbt.SpuOptimizationTaskId == request.SpuOptimizationTaskId && sbt.BelongTeamId == uInfo.department.Id).ToOne();
            if (spuOptimizationBargainTeamTask == null)
                throw new BusinessException($"待优化任务{request.SpuOptimizationTaskId}中不存在议价组{uInfo.department.Id}/{uInfo.department.DepartmentName}的子任务");
            var skuIdList = fsql.Select<SkuOptimizationTask>().Where(s => s.SpuOptimizationTaskId == request.SpuOptimizationTaskId).ToList(s => s.SkuId);
            #endregion

            #region DBOperation
            List<SpuOptimizationCompetitiveTenderTask> insertSpuOptimizationCompetitiveTenderTaskList = new List<SpuOptimizationCompetitiveTenderTask>();
            List<long> updateCompetitiveTenderTaskIdList = new List<long>();
            #endregion

            //var skuList = request.ItemList.Select(x => x.SkuId).Distinct().ToList();
            var purchaseSkuIdList = request.ItemList.Select(x => x.PurchaseSkuId).Distinct().ToList();

            //查询竞标任务
            var competitiveTenderTaskList = fsql.Select<SpuOptimizationCompetitiveTenderTask>()
                                                .Where(ct => ct.BargainTeamId == uInfo.user.DepartmentId &&
                                                             ct.SpuOptimizationTaskId == request.SpuOptimizationTaskId &&
                                                             ct.SchemeGroupId == request.SchemeGroupId)
                                                .ToList();

            //查询配件关联的采购方案
            var relationPurchaseSchemeList = fsql.Select<PurchaseScheme>()
                                                 .Where(ps => ps.SchemeGroupId == request.SchemeGroupId &&
                                                              ps.BelongBargainTeamId == uInfo.user.DepartmentId &&
                                                              fsql.Select<PurchaseSchemeProductSku>()
                                                                  .Where(pss => skuIdList.Contains(pss.SkuId) &&
                                                                                purchaseSkuIdList.Contains(pss.PurchaseSkuId) &&
                                                                                pss.SkuPurchaseSchemeId == ps.Id).Any())
                                                 .ToList();


            //筛选出不在竞标任务中的采购方案
            var noJoinCompetitiveTenderPurchaseSchemeList = relationPurchaseSchemeList.Where(ps => !competitiveTenderTaskList.Any(ct => ct.SchemeId == ps.Id)).ToList();
            var noJoinCompetitiveTenderPurchaseSchemeIdList = noJoinCompetitiveTenderPurchaseSchemeList.Select(x => x.Id).ToList();
            //批量更新配件
            purchaseSchemeBusiness.BatchEditPurchaseSkuActualPrice(request.Map<BatchEditPurchaseSkuActualPriceRequest>(), noJoinCompetitiveTenderPurchaseSchemeIdList, userId);

            if (noJoinCompetitiveTenderPurchaseSchemeList.Count() > 0)
            {
                insertSpuOptimizationCompetitiveTenderTaskList.AddRange(noJoinCompetitiveTenderPurchaseSchemeList.Select(ps => new SpuOptimizationCompetitiveTenderTask()
                {
                    Id = idGenerator.NewLong(),
                    CreateTime = DateTime.Now,
                    BargainTeamId = uInfo.department.Id,
                    IsUpdateQuotedPrice = true,
                    SchemeGroupId = ps.SchemeGroupId,
                    SchemeId = ps.Id,
                    SkuId = ps.SkuId,
                    SpuOptimizationBargainTeamTaskId = spuOptimizationBargainTeamTask.Id,
                    SpuOptimizationTaskId = request.SpuOptimizationTaskId,
                    UpdateTime = DateTime.Now
                }));
            }
            if (competitiveTenderTaskList.Count() > 0)
                updateCompetitiveTenderTaskIdList.AddRange(competitiveTenderTaskList.Select(ct => ct.Id).ToList());

            fsql.Transaction(() =>
            {
                if (insertSpuOptimizationCompetitiveTenderTaskList.Count() > 0)
                    fsql.Insert(insertSpuOptimizationCompetitiveTenderTaskList).ExecuteAffrows();
                if (updateCompetitiveTenderTaskIdList.Count() > 0)
                    fsql.Update<SpuOptimizationCompetitiveTenderTask>(updateCompetitiveTenderTaskIdList)
                        .Set(ct => ct.IsUpdateQuotedPrice, true)
                        .Set(ct => ct.UpdateTime, DateTime.Now)
                        .ExecuteAffrows();
            });
        }

        /// <summary>
        /// 完成优化
        /// </summary>
        /// <param name="taskId"></param>
        /// <param name="userId"></param>
        /// <exception cref="BusinessException"></exception>
        public void CompleteOptimization(long taskId, string userId)
        {
            #region 获取用户和部门信息
            var uInfo = userBusiness.GetisBargainTeamByUserId(userId, true);
            #endregion

            #region 业务验证
            var spuOptimizationTask = fsql.Select<SpuOptimizationTask>(taskId).ToOne();
            if (spuOptimizationTask == null)
                throw new BusinessException($"待优化任务{taskId}不存在");
            if (spuOptimizationTask.IsOptimizationCompleted == true)
                throw new BusinessException("待优化任务已完成");

            var spuOptimizationBargainTeamTaskList = fsql.Select<SpuOptimizationBargainTeamTask>()
                                                         .Where(sbt => sbt.SpuOptimizationTaskId == taskId)
                                                         .ToList();
            var currentspuOptimizationBargainTeamTask = spuOptimizationBargainTeamTaskList.FirstOrDefault(sc => sc.BelongTeamId == uInfo.department.Id);
            if (currentspuOptimizationBargainTeamTask == null)
                throw new BusinessException($"未找到议价组{uInfo.department.DepartmentName}的议价子任务");
            if (currentspuOptimizationBargainTeamTask.IsOptimizationCompleted == true)
                throw new BusinessException($"{uInfo.department.DepartmentName}的议价子任务已完成");

            var skuIdList = fsql.Select<SkuOptimizationTask>()
                                .Where(s => s.SpuOptimizationTaskId == taskId)
                                .ToList(s => s.SkuId);

            //查询全部竞标任务
            var allBargainTeamCompetitiveTenderTaskList = fsql.Select<SpuOptimizationCompetitiveTenderTask>()
                                                              .Where(ct => ct.SpuOptimizationTaskId == taskId)
                                                              .ToList();

            //查询当前议价组的竞标任务
            var currentBargainTeamCompetitiveTenderTaskList = allBargainTeamCompetitiveTenderTaskList.Where(ct => ct.BargainTeamId == uInfo.department.Id).ToList();
            if (currentBargainTeamCompetitiveTenderTaskList.Count() == 0)
                throw new BusinessException($"议价组{uInfo.department.DepartmentName}没有参与竞标的采购方案,不能完成优化任务");
            var currentBargainTeamCompetitiveTenderSchemeIdList = currentBargainTeamCompetitiveTenderTaskList.Select(ct => ct.SchemeId).ToList();

            #region 验证该议价组的符合sku条件的采购方案是否都参与投标
            var waitCheckPurchaseSchemeIdList = fsql.Select<PurchaseScheme>()
                                                    .Where(ps => ps.BelongBargainTeamId == uInfo.user.DepartmentId &&
                                                                 skuIdList.Contains(ps.SkuId))
                                                    .ToList(ps => ps.Id);

            if (waitCheckPurchaseSchemeIdList.Count() == 0)
                throw new BusinessException($"议价组{uInfo.department.DepartmentName}没有参与竞标的采购方案,不能完成优化任务");
            var noJoinCompetitiveTenderSchemeIdList = waitCheckPurchaseSchemeIdList.Except(currentBargainTeamCompetitiveTenderSchemeIdList);
            if (noJoinCompetitiveTenderSchemeIdList.Count() > 0)
                throw new BusinessException($"议价组{uInfo.department.DepartmentName}存在{noJoinCompetitiveTenderSchemeIdList.Count()}个符合条件但未参与竞标的采购方案");
            #endregion

            #region 验证该议价组参与投标的采购方案是否都完成报价
            if (currentBargainTeamCompetitiveTenderTaskList.Any(ct => ct.IsUpdateQuotedPrice == false))
                throw new BusinessException($"议价组{uInfo.department.DepartmentName}存在未更新报价的投标");
            #endregion

            currentspuOptimizationBargainTeamTask.IsOptimizationCompleted = true;
            #endregion

            IUpdate<SpuOptimizationBargainTeamTask> updateBargainTask = null;
            IUpdate<SpuOptimizationTask> updateSpuTask = null;
            IUpdate<SpuTotalSaleInfo> updateSpuSaleInfo = null;
            IUpdate<TimeLimitTask> updateTimeLimitTask = null;
            IUpdate<SpuOptimizationCompetitiveTenderTask> updateCompetitiveTenderTask = null;

            if (!spuOptimizationBargainTeamTaskList.Any(sc => sc.IsOptimizationCompleted == false))
            {
                //全部完成

                #region 更新spu销量表
                var spuSaleInfo = fsql.Select<SpuTotalSaleInfo>(spuOptimizationTask.ProductId).ToOne();
                if (spuSaleInfo == null)

                    throw new BusinessException($"未找到spu{spuOptimizationTask.ProductId}销量");

                updateSpuSaleInfo = fsql.Update<SpuTotalSaleInfo>(spuOptimizationTask.ProductId)
                                        .SetIf(spuSaleInfo.IsFirstPurchaseCompleted == false, s => s.IsFirstPurchaseCompleted, true)
                                        .SetIf(spuSaleInfo.IsFirstPurchaseCompleted == false, s => s.FirstPurchaseCompletedItemCount == s.ItemCount)
                                        .SetIf(spuSaleInfo.IsFirstPurchaseCompleted == true &&
                                               spuSaleInfo.IsFirstOptimizationCompleted == false, s => s.IsFirstOptimizationCompleted, true)
                                        .SetIf(spuSaleInfo.IsFirstPurchaseCompleted == true &&
                                               spuSaleInfo.IsFirstOptimizationCompleted == false, s => s.FirstOptimizationCompletedItemCount == s.ItemCount)
                                        .Set(s => s.LastOptimizationItemCount == s.ItemCount)
                                        .Set(s => s.LastOptimizationTime, DateTime.Now)
                                        .Set(s => s.UpdateTime, DateTime.Now);
                #endregion

                #region 更新待优化任务
                updateSpuTask = fsql.Update<SpuOptimizationTask>(spuOptimizationTask.Id)
                                 .Set(t => t.IsOptimizationCompleted, true)
                                 .Set(t => t.CompletionTime, DateTime.Now);
                #endregion

                #region 更新待优化限时任务
                updateTimeLimitTask = fsql.Update<TimeLimitTask>().Set(t => t.CompletionTime, DateTime.Now)
                                          .Set(t => t.IsTimely == (DateTime.Now < t.ExpirationTime ? true : false))
                                          .Where(t => t.TaskId == spuOptimizationTask.Id &&
                                                      t.CompletionTime == null &&
                                                      t.TaskType == Enums.TimeLimitTaskType.待议价任务);
                #endregion

                #region 评选中标结果
                var allBargainTeamCompetitiveTenderSchemeIdList = allBargainTeamCompetitiveTenderTaskList.Select(ct => ct.SchemeId).ToList();
                var allBargainTeamPurchaseSchemeList = purchaseSchemeBusiness.GetPurchaseSchemeList(new QuerySchemeRequest()
                {
                    SchemeIdList = allBargainTeamCompetitiveTenderSchemeIdList,
                    IncludePurchaseSkuBasicInfo = 0
                });
                var victoryCompetitiveTenderTaskList = VictoryPlanSelection(allBargainTeamCompetitiveTenderTaskList, allBargainTeamPurchaseSchemeList);
                var victoryCompetitiveTenderTaskIdList = victoryCompetitiveTenderTaskList.Select(ct => ct.Id).ToList();
                updateCompetitiveTenderTask = fsql.Update<SpuOptimizationCompetitiveTenderTask>(victoryCompetitiveTenderTaskIdList)
                                                  .Set(ct => ct.IsWin, true);
                #endregion
            }

            #region 更新待优化议价组任务
            updateBargainTask = fsql.Update<SpuOptimizationBargainTeamTask>(currentspuOptimizationBargainTeamTask.Id)
                                    .Set(sc => sc.IsOptimizationCompleted, true)
                                    .Set(sc => sc.CompletionTime, DateTime.Now);
            #endregion

            fsql.Transaction(() =>
            {
                updateSpuTask?.ExecuteAffrows();
                updateBargainTask?.ExecuteAffrows();
                updateSpuSaleInfo?.ExecuteAffrows();
                updateTimeLimitTask?.ExecuteAffrows();
                updateCompetitiveTenderTask?.ExecuteAffrows();
            });
        }

        /// <summary>
        /// 查询待优化任务
        /// </summary>
        /// <param name="request"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        /// <exception cref="BusinessException"></exception>
        public ListResponse<SpuOptimizationTaskResponse> GetNoCompletionSkuOptimizationTask(QueryNoCompletionOptimizationTaskRequest request, string userId)
        {
            request.EndTime = request.EndTime.Date.AddDays(1).AddSeconds(-1);
            var uInfo = userBusiness.GetisBargainTeamByUserId(userId, true);

            ISelect<SpuOptimizationTask> select = null;
            if (request.SpuOptimizationTaskId != null && request.SpuOptimizationTaskId != 0)
            {
                select = fsql.Select<SpuOptimizationTask>(request.SpuOptimizationTaskId);
            }
            else
            {
                string spuKeyWords = string.Empty, skuKeyWords = string.Empty;
                if (!string.IsNullOrEmpty(request.SpuOrSku))
                {
                    if (Regex.IsMatch(request.SpuOrSku, @"^\d{2,10}$"))
                        spuKeyWords = request.SpuOrSku;
                    else if (Regex.IsMatch(request.SpuOrSku, @"^\w{2,20}$"))
                        skuKeyWords = request.SpuOrSku;
                }

                select = fsql.Select<SpuOptimizationTask>()
                             .Where(t => t.IsOptimizationCompleted == false &&
                                         t.CreateTime >= request.StartTime &&
                                         t.CreateTime <= request.EndTime)
                             .WhereIf(request.BelongShopId != null && request.BelongShopId != 0, t => t.BelongShopId == request.BelongShopId)
                             .WhereIf(!string.IsNullOrEmpty(request.JDSku) ||
                                      !string.IsNullOrEmpty(skuKeyWords), t => fsql.Select<SkuOptimizationTask>()
                                                                                   .Where(st => st.SpuOptimizationTaskId == t.Id)
                                                                                   .WhereIf(!string.IsNullOrEmpty(request.JDSku), st => st.JDSkuId == request.JDSku)
                                                                                   .WhereIf(!string.IsNullOrEmpty(skuKeyWords), st => st.SkuId == skuKeyWords)
                                                                                   .Any())
                             .WhereIf(!string.IsNullOrEmpty(request.TitleKeywords), t => t.ProductTitle.Contains(request.TitleKeywords))
                             .WhereIf(!string.IsNullOrEmpty(spuKeyWords), t => t.ProductId == spuKeyWords);
            }

            var taskList = select.OrderByDescending(t => t.CreateTime)
                                 .Count(out var total)
                                 .Page(request.PageIndex, request.PageSize)
                                 .ToList<SpuOptimizationTaskResponse>();
            if (taskList.Count() == 0)
                return new ListResponse<SpuOptimizationTaskResponse>() { TotalCount = 0, Items = null };

            var spuTaskIdList = taskList.Select(t => t.Id).ToList();

            #region 获取议价组任务
            var bargainTeamTaskList = fsql.Select<SpuOptimizationBargainTeamTask>()
                                          .Where(sbt => spuTaskIdList.Contains(sbt.SpuOptimizationTaskId))
                                          .ToList<SpuOptimizationBargainTeamTaskResponse>();
            var bargainTeamIdList = bargainTeamTaskList.Select(x => x.BelongTeamId).Distinct().ToList();
            #endregion

            #region 获取SKU优化任务
            var skuTaskList = fsql.Select<SkuOptimizationTask, Model.Db.ProductSku>()
                                  .LeftJoin((st, ps) => st.SkuId == ps.Id)
                                  .Where((st, ps) => spuTaskIdList.Contains(st.SpuOptimizationTaskId))
                                  .ToList((st, ps) => new SkuOptimizationTaskResponse
                                  {
                                      CreateTime = st.CreateTime,
                                      Id = st.Id,
                                      JDSkuId = st.JDSkuId,
                                      Logo = ps.Logo,
                                      PreItemCount = st.PreItemCount,
                                      PrePurchaseAmount = st.PrePurchaseAmount,
                                      SkuId = st.SkuId,
                                      SpuOptimizationTaskId = st.SpuOptimizationTaskId,
                                      SkuName = ps.SkuName,
                                      Price = ps.Price
                                  });
            var skuIdList = skuTaskList.Select(st => st.SkuId).ToList();
            #endregion

            #region 限时任务
            var timelimitTaskList = fsql.Select<TimeLimitTask>()
                                        .Where(t => t.TaskType == Enums.TimeLimitTaskType.待议价任务 && spuTaskIdList.Contains(t.TaskId))
                                        .ToList<TimeLimitTaskResponse>();
            #endregion

            #region 获取采购方案
            if (skuIdList.Count() == 0 && bargainTeamIdList.Count() == 0)
                return new ListResponse<SpuOptimizationTaskResponse>()
                {
                    Items = null,
                    TotalCount = 0
                };
            var purchaseSchemeList = purchaseSchemeBusiness.GetPurchaseSchemeList(new QuerySchemeRequest()
            {
                SkuIdList = skuIdList,
                BargainTeamIdList = bargainTeamIdList,
                IncludePurchaseSkuBasicInfo = 1,
                IncludePurchaseSkuStatisticsInfo = 1
            });
            #endregion

            #region 获取采购方案分组
            var purchaseSchemeGroupIdList = purchaseSchemeList.Select(ps => ps.SchemeGroupId).Distinct().ToList();
            var purchaseSchemeGroupList = fsql.Select<PurchaseSchemeGroup>(purchaseSchemeGroupIdList).ToList<PurchaseSchemeGroupResponse>();
            #endregion

            foreach (var task in taskList)
            {
                task.BargainTeamTaskList = bargainTeamTaskList.Where(sbt => sbt.SpuOptimizationTaskId == task.Id).ToList();
                task.TimeLimitTask = timelimitTaskList.FirstOrDefault(t => t.TaskId == task.Id);
                if (task.TimeLimitTask != null)
                    timeLimitRules.CalculateLessTimeForWorkHour(task.TimeLimitTask.ExpirationTime.Value);
                task.IsCompletedByCurrentTeam = task.BargainTeamTaskList.FirstOrDefault(sbt => sbt.BelongTeamId == uInfo.department.Id)?.IsOptimizationCompleted == true;
                task.SkuOptimizationTaskList = skuTaskList.Where(st => st.SpuOptimizationTaskId == task.Id).ToList();

                #region 合并分组/采购商/配件
                var currentTaskSkuIdList = task.SkuOptimizationTaskList.Select(st => st.SkuId).ToList();
                var currentPurchaseSchemeGroups = purchaseSchemeList.Where(p => currentTaskSkuIdList.Contains(p.SkuId) &&
                                                                              p.BelongBargainTeamId == uInfo.department.Id)
                                                                  .GroupBy(p => p.SchemeGroupId)
                                                                  .ToList();
                task.MergePurchaseScemeGroupList = new List<MergePurchaseSchemeGroupResponse>();
                foreach (var schemeGroup in currentPurchaseSchemeGroups)
                {
                    var mergeSchemeGroup = new MergePurchaseSchemeGroupResponse()
                    {
                        Id = schemeGroup.Key,
                        GroupName = purchaseSchemeGroupList.FirstOrDefault(g => g.Id == schemeGroup.Key)?.GroupName
                    };
                    task.MergePurchaseScemeGroupList.Add(mergeSchemeGroup);

                    var schemeList = schemeGroup.ToList();

                    foreach (var scheme in schemeList)
                    {
                        foreach (var psp in scheme.PurchaseSchemeProductList)
                        {
                            var mergePurchaser = mergeSchemeGroup.PurchaserList.FirstOrDefault(p => p.Id == psp.PurchaserId);
                            if (mergePurchaser == null)
                            {
                                mergePurchaser = scheme.PurchaserList.FirstOrDefault(p => p.Id == psp.PurchaserId)?.Map<MergePurchaserResponse>();
                                if (mergePurchaser == null)
                                    throw new BusinessException($"匹配采购商异常 schemeId {scheme.Id} pspProductId {psp.ProductId}");
                                mergeSchemeGroup.PurchaserList.Add(mergePurchaser);
                            }
                            foreach (var pss in psp.PurchaseSchemeProductSkuList)
                            {
                                var mergePss = mergePurchaser.MergePurchaseSchemeProductSkuList.FirstOrDefault(mpss => mpss.PurchaseSkuId == pss.PurchaseSkuId);
                                if (mergePss == null)
                                {
                                    mergePss = pss.Map<MergePurchaseSchemeProductSkuResponse>();
                                    mergePss.PurchaserId = mergePurchaser.Id;
                                    mergePurchaser.MergePurchaseSchemeProductSkuList.Add(mergePss);
                                }
                            }
                        }
                    }
                }
                #endregion
            }

            return new ListResponse<SpuOptimizationTaskResponse>()
            {
                Items = taskList,
                TotalCount = total
            };
        }

        /// <summary>
        /// 评选结果
        /// </summary>
        /// <param name="competitiveTenderTaskList"></param>
        /// <param name="purchaseSchemeList"></param>
        /// <returns></returns>
        private IList<SpuOptimizationCompetitiveTenderTask> VictoryPlanSelection(IList<SpuOptimizationCompetitiveTenderTask> competitiveTenderTaskList,
                                                                                 IList<PurchaseSchemeResponse> purchaseSchemeList)
        {
            var victoryList = new List<SpuOptimizationCompetitiveTenderTask>();
            var psGroups = purchaseSchemeList.GroupBy(ps => ps.SkuId);
            foreach (var psGroup in psGroups)
            {
                var psListOrderByCostDescList = psGroup.OrderByDescending(ps => ps.BargainingCost ?? ps.DefaultCost).ToList();
                var minCostScheme = psListOrderByCostDescList.FirstOrDefault();
                var competitiveTenderTask = competitiveTenderTaskList.FirstOrDefault(ct => ct.SchemeId == minCostScheme.Id);
                victoryList.Add(competitiveTenderTask);
            }
            return victoryList;
        }

        /// <summary>
        /// 限时任务超时回调
        /// </summary>
        /// <param name="taskId"></param>
        public void TimeLimitTaskTimeOutCallBack(long taskId)
        {
            try
            {
                var spuOptimizationTask = fsql.Select<SpuOptimizationTask>(taskId).ToOne();
                if (spuOptimizationTask == null)
                    throw new BusinessException($"待优化任务{taskId}不存在");
                if (spuOptimizationTask.IsOptimizationCompleted == true)
                    throw new BusinessException("待优化任务已完成");

                IUpdate<SpuOptimizationTask> updateSpuTask = null;
                IUpdate<SpuTotalSaleInfo> updateSpuSaleInfo = null;
                IUpdate<SpuOptimizationCompetitiveTenderTask> updateCompetitiveTenderTask = null;

                var spuOptimizationBargainTeamTaskList = fsql.Select<SpuOptimizationBargainTeamTask>()
                                                             .Where(sbt => sbt.SpuOptimizationTaskId == taskId)
                                                             .ToList();

                if (spuOptimizationBargainTeamTaskList.Any(sc => sc.IsOptimizationCompleted == true))
                {
                    //任意一个议价组完成任务,该优化任务视为完成

                    var compleptionBargainTeamIdList = spuOptimizationBargainTeamTaskList.Where(sbt => sbt.IsOptimizationCompleted == true)
                                                                                             .Select(sbt => sbt.BelongTeamId)
                                                                                             .Distinct()
                                                                                             .ToList();

                    //已完成议价任务的竞标任务
                    var compleptionBargainTeamCompetitiveTenderTaskList = fsql.Select<SpuOptimizationCompetitiveTenderTask>()
                                                                              .Where(ct => ct.SpuOptimizationTaskId == taskId &&
                                                                                           compleptionBargainTeamIdList.Contains(ct.BargainTeamId))
                                                                              .ToList();

                    #region 更新spu销量表
                    var spuSaleInfo = fsql.Select<SpuTotalSaleInfo>(spuOptimizationTask.ProductId).ToOne();
                    if (spuSaleInfo == null)

                        throw new BusinessException($"未找到spu{spuOptimizationTask.ProductId}销量");

                    updateSpuSaleInfo = fsql.Update<SpuTotalSaleInfo>(spuOptimizationTask.ProductId)
                                            .SetIf(spuSaleInfo.IsFirstPurchaseCompleted == false, s => s.IsFirstPurchaseCompleted, true)
                                            .SetIf(spuSaleInfo.IsFirstPurchaseCompleted == false, s => s.FirstPurchaseCompletedItemCount == s.ItemCount)
                                            .SetIf(spuSaleInfo.IsFirstPurchaseCompleted == true &&
                                                   spuSaleInfo.IsFirstOptimizationCompleted == false, s => s.IsFirstOptimizationCompleted, true)
                                            .SetIf(spuSaleInfo.IsFirstPurchaseCompleted == true &&
                                                   spuSaleInfo.IsFirstOptimizationCompleted == false, s => s.FirstOptimizationCompletedItemCount == s.ItemCount)
                                            .Set(s => s.LastOptimizationItemCount == s.ItemCount)
                                            .Set(s => s.LastOptimizationTime, DateTime.Now)
                                            .Set(s => s.UpdateTime, DateTime.Now);
                    #endregion

                    #region 更新待优化任务
                    updateSpuTask = fsql.Update<SpuOptimizationTask>(spuOptimizationTask.Id)
                                        .Set(t => t.IsOptimizationCompleted, true)
                                        .Set(t => t.CompletionTime, DateTime.Now);
                    #endregion

                    #region 评选竞标结果
                    var compleptionBargainTeamPurchaseSchemeIdList = compleptionBargainTeamCompetitiveTenderTaskList.Select(ct => ct.SchemeId).ToList();
                    var compleptionBargainTeamPurchaseSchemeList = purchaseSchemeBusiness.GetPurchaseSchemeList(new QuerySchemeRequest()
                    {
                        SchemeIdList = compleptionBargainTeamPurchaseSchemeIdList,
                        IncludePurchaseSkuBasicInfo = 0
                    });
                    var victoryCompetitiveTenderTaskList = VictoryPlanSelection(compleptionBargainTeamCompetitiveTenderTaskList, compleptionBargainTeamPurchaseSchemeList);
                    var victoryCompetitiveTenderTaskIdList = victoryCompetitiveTenderTaskList.Select(ct => ct.Id).ToList();
                    updateCompetitiveTenderTask = fsql.Update<SpuOptimizationCompetitiveTenderTask>(victoryCompetitiveTenderTaskIdList)
                                                      .Set(ct => ct.IsWin, true);
                    #endregion
                }

                fsql.Transaction(() =>
                {
                    updateSpuTask?.ExecuteAffrows();
                    updateSpuSaleInfo?.ExecuteAffrows();
                    updateCompetitiveTenderTask?.ExecuteAffrows();
                });
            }
            catch (Exception ex)
            {
                nLogManager.Default().Error(ex, "限时任务超时回调失败");
            }
        }
    }
}