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

namespace BBWY.Server.Business.Sync
{
    public class ProductSyncBusiness : BaseSyncBusiness, IDenpendency
    {
        private ProductBusiness productBusiness;

        private ConcurrentDictionary<string, string> categoryCache;

        public ProductSyncBusiness(RestApiService restApiService,
                               IOptions<GlobalConfig> options,
                               NLogManager nLogManager,
                               IFreeSql fsql,
                               IIdGenerator idGenerator,
                               TaskSchedulerManager taskSchedulerManager,
                               VenderBusiness venderBusiness,
                               ProductBusiness productBusiness,
                               YunDingBusiness yunDingBusiness) : base(restApiService,
                                                                     options,
                                                                     nLogManager,
                                                                     fsql,
                                                                     idGenerator,
                                                                     taskSchedulerManager,
                                                                     venderBusiness,
                                                                     yunDingBusiness)
        {
            this.productBusiness = productBusiness;
            this.categoryCache = new ConcurrentDictionary<string, string>();
        }

        private string GetMainSkuId(IList<ProductSkuResponse> skuList)
        {
            var maxPrice = skuList.Max(s => s.Price);
            var sku = skuList.FirstOrDefault(s => s.Price == maxPrice && s.State == 1);
            return sku?.Id ?? string.Empty;
        }

        private bool CheckMainSkuState(IList<ProductSkuResponse> skuList, string mainSkuId)
        {
            if (string.IsNullOrEmpty(mainSkuId))
                return false;
            var mainSku = skuList.FirstOrDefault(s => s.Id == mainSkuId);
            if (mainSku == null || mainSku.State != 1)
                return false;
            return true;
        }

        private void SyncProduct(ShopResponse shop, ProductListResponse productList)
        {
            var currentProductId = "";
            try
            {
                var shopId = long.Parse(shop.ShopId);
                List<Product> insertProductList = new List<Product>();
                List<IUpdate<Product>> updateProductList = new List<IUpdate<Product>>();

                List<ProductSku> inserSkuList = new List<ProductSku>();
                List<IUpdate<ProductSku>> updateProductSkuList = new List<IUpdate<ProductSku>>();

                var productIds = productList.Items.Select(p => p.Id);
                var dbProducts = fsql.Select<Product>().Where(p => p.ShopId == shopId && productIds.Contains(p.Id)).ToList();
                var dbProductSkus = fsql.Select<ProductSku>().Where(s => s.ShopId == shopId && productIds.Contains(s.ProductId)).ToList();

                foreach (var product in productList.Items)
                {
                    Thread.Sleep(200);
                    currentProductId = product.Id;

                    #region 检查sku
                    var skuList = productBusiness.GetProductSkuList(new SearchProductSkuRequest()
                    {
                        AppKey = shop.AppKey,
                        AppSecret = shop.AppSecret,
                        AppToken = shop.AppToken,
                        Platform = shop.PlatformId,
                        Spu = product.Id,
                        IsContainSource = true
                    });
                    if (skuList == null || skuList.Count() == 0)
                        continue;

                    //排查已删除的sku
                    var currentDbSkus = dbProductSkus.Where(dbsku => dbsku.ProductId == product.Id).ToList();
                    var deletedSkuList = currentDbSkus.Where(dbsku => skuList.Count(s => s.Id == dbsku.Id) == 0).ToList();
                    if (deletedSkuList.Count() > 0)
                    {
                        foreach (var deletedSku in deletedSkuList)
                        {
                            var update = fsql.Update<ProductSku>(deletedSku.Id).Set(s => s.State, 4);
                            updateProductSkuList.Add(update);
                        }
                    }

                    foreach (var sku in skuList)
                    {
                        var categoryId = sku.Source.Value<int>("categoryId");
                        var dbSku = dbProductSkus.FirstOrDefault(s => s.Id == sku.Id);
                        if (dbSku == null)
                        {
                            inserSkuList.Add(new ProductSku()
                            {
                                Id = sku.Id,
                                CreateTime = sku.CreateTime ?? DateTime.Now,
                                Logo = sku.Logo,
                                Platform = shop.PlatformId,
                                Price = sku.Price,
                                ProductId = sku.ProductId,
                                ShopId = shopId,
                                Title = sku.Title,
                                State = sku.State,
                                CategoryId = categoryId
                            });
                        }
                        else if (dbSku.State != sku.State || dbSku.Price != sku.Price || dbSku.CategoryId != categoryId)
                        {
                            var update = fsql.Update<ProductSku>(dbSku.Id)
                                             .Set(s => s.State, sku.State)
                                             .Set(s => s.Price, sku.Price)
                                             .Set(s => s.CategoryId, categoryId);
                            updateProductSkuList.Add(update);
                        }
                    }
                    #endregion

                    #region 检查产品
                    var dbProduct = dbProducts.FirstOrDefault(dbp => dbp.Id == product.Id);
                    if (dbProduct == null)
                    {
                        insertProductList.Add(new Product()
                        {
                            Id = product.Id,
                            CreateTime = product.CreateTime ?? DateTime.Now,
                            Platform = shop.PlatformId,
                            ProductItemNum = product.ProductItemNum,
                            ShopId = shopId,
                            Title = product.Title,
                            State = product.State,
                            MainSkuId = GetMainSkuId(skuList)
                        });
                    }
                    else if (dbProduct.State != product.State || !CheckMainSkuState(skuList, dbProduct.MainSkuId))
                    {
                        string newMainSkuId = string.Empty;
                        if (!CheckMainSkuState(skuList, dbProduct.MainSkuId))
                            newMainSkuId = GetMainSkuId(skuList);

                        var update = fsql.Update<Product>(product.Id).SetIf(dbProduct.State != product.State, p => p.State, product.State)
                                                                     .SetIf(!string.IsNullOrEmpty(newMainSkuId), p => p.MainSkuId, newMainSkuId);
                        updateProductList.Add(update);
                    }
                    #endregion
                }

                fsql.Transaction(() =>
                {
                    fsql.Insert(insertProductList).ExecuteAffrows();
                    fsql.Insert(inserSkuList).ExecuteAffrows();
                    if (updateProductList.Count > 0)
                        foreach (var update in updateProductList)
                            update.ExecuteAffrows();
                    if (updateProductSkuList.Count > 0)
                        foreach (var update in updateProductSkuList)
                            update.ExecuteAffrows();

                });
            }
            catch (Exception ex)
            {
                throw new Exception(currentProductId, ex);
            }
        }

        private void SyncProduct(ShopResponse shop, bool IsSyncAllProduct = false)
        {
            try
            {
                var shopId = long.Parse(shop.ShopId);
                var dbProductList = fsql.Select<Product>().Where(p => p.ShopId == shopId).ToList();
                var dbProductSkuList = fsql.Select<ProductSku>().Where(p => p.ShopId == shopId).ToList();

                List<ProductResponse> productList = new List<ProductResponse>();
                List<ProductSkuResponse> productSkuList = new List<ProductSkuResponse>();

                List<Product> insertProductList = new List<Product>();
                List<ProductSku> insertProductSkuList = new List<ProductSku>();

                List<IUpdate<Product>> updateProductList = new List<IUpdate<Product>>();
                List<IUpdate<ProductSku>> updateProductSkuList = new List<IUpdate<ProductSku>>();

                var request = new SearchProductRequest()
                {
                    PageSize = 50,
                    PageIndex = 1,
                    AppKey = shop.AppKey,
                    AppSecret = shop.AppSecret,
                    AppToken = shop.AppToken,
                    Platform = shop.PlatformId
                };
                while (true)
                {
                    var currentProductList = productBusiness.GetProductList(request);
                    if (currentProductList == null || currentProductList.Count == 0)
                        break;
                    productList.AddRange(currentProductList.Items);

                    foreach (var product in currentProductList.Items)
                    {
                        var currentSkuList = productBusiness.GetProductSkuList(new SearchProductSkuRequest()
                        {
                            AppKey = shop.AppKey,
                            AppSecret = shop.AppSecret,
                            AppToken = shop.AppToken,
                            Platform = shop.PlatformId,
                            Spu = product.Id,
                            IsContainSource = true
                        });
                        if (currentSkuList == null || currentSkuList.Count() == 0)
                            continue;
                        productSkuList.AddRange(currentSkuList);
                    }

                    if (currentProductList.Items.Count < 50 || !IsSyncAllProduct)
                        break;
                    request.PageIndex++;
                    Thread.Sleep(1000);
                }

                #region 找出新增的产品
                var newProductList = productList.Where(p => !dbProductList.Any(dp => dp.Id == p.Id)).ToList();
                if (newProductList.Count() > 0)
                {
                    insertProductList.AddRange(newProductList.Select(p => new Product()
                    {
                        Id = p.Id,
                        CreateTime = p.CreateTime,
                        Title = p.Title,
                        State = p.State,
                        ShopId = shopId,
                        Platform = shop.PlatformId,
                        ProductItemNum = p.ProductItemNum,
                        MainSkuId = productSkuList.FirstOrDefault(s => s.ProductId == p.Id)?.Id
                    }));
                }
                #endregion

                #region 找出变化的产品 (状态,标题)
                var stateChangeProductList = productList.Where(p => dbProductList.Any(dp => dp.Id == p.Id && (dp.State != p.State || dp.Title != p.Title))).ToList();
                if (stateChangeProductList.Count() > 0)
                {
                    foreach (var product in stateChangeProductList)
                    {
                        var update = fsql.Update<Product>(product.Id).Set(p => p.State, product.State)
                                                                     .Set(p => p.Title, product.Title);
                        updateProductList.Add(update);
                    }
                }
                #endregion

                #region 找出接口查不出的产品
                var goneProductList = dbProductList.Where(dp => !productList.Any(p => p.Id == dp.Id)).ToList();
                if (goneProductList.Count() > 0)
                {
                    var goneProductIdList = goneProductList.Select(p => p.Id).ToList();
                    var update = fsql.Update<Product>().Set(p => p.State, -1).Where(p => goneProductIdList.Contains(p.Id));
                    updateProductList.Add(update);
                }
                #endregion

                #region 找出新增的SKU
                var newProductSkuList = productSkuList.Where(p => !dbProductSkuList.Any(dp => dp.Id == p.Id)).ToList();
                if (newProductSkuList.Count() > 0)
                {
                    insertProductSkuList.AddRange(newProductSkuList.Select(p => new ProductSku()
                    {
                        Id = p.Id,
                        CreateTime = p.CreateTime,
                        Title = p.Title,
                        State = p.State,
                        ShopId = shopId,
                        Platform = shop.PlatformId,
                        Logo = p.Logo,
                        ProductId = p.ProductId,
                        Price = p.Price,
                        CategoryId = p.Source.Value<int>("categoryId"),
                        CategoryName = GetCategoryName(shop, p.Source.Value<string>("categoryId"))
                    }));
                }
                #endregion

                #region 找出状态变化的SKU
                var stateChangeProductSkuList = productSkuList.Where(p => dbProductSkuList.Any(dp => dp.Id == p.Id && (dp.State != p.State || dp.Title != p.Title || dp.Price != p.Price || dp.Logo != p.Logo))).ToList();
                if (stateChangeProductSkuList.Count() > 0)
                {
                    foreach (var productSku in stateChangeProductSkuList)
                    {
                        var update = fsql.Update<ProductSku>(productSku.Id).Set(p => p.State, productSku.State)
                                                                           .Set(p => p.Title, productSku.Title)
                                                                           .Set(p => p.Price, productSku.Price)
                                                                           .Set(p => p.Logo, productSku.Logo);
                        updateProductSkuList.Add(update);
                    }
                }
                #endregion

                #region 找出缺少类目的sku
                var noCategoryProductList = productSkuList.Where(p => dbProductSkuList.Any(dp => dp.Id == p.Id && string.IsNullOrEmpty(dp.CategoryName))).ToList();
                if (noCategoryProductList.Count() > 0)
                {
                    foreach (var productSku in noCategoryProductList)
                    {
                        var categoryName = GetCategoryName(shop, productSku.Source.Value<string>("categoryId"));
                        var update = fsql.Update<ProductSku>(productSku.Id).Set(p => p.CategoryName, categoryName);
                        updateProductSkuList.Add(update);
                    }
                }
                #endregion

                #region 找出接口查不出的SKU
                var goneProductSkuList = dbProductSkuList.Where(dp => !productSkuList.Any(p => p.Id == dp.Id)).ToList();
                if (goneProductSkuList.Count() > 0)
                {
                    var goneProductSkuIdList = goneProductSkuList.Select(p => p.Id).ToList();
                    var update = fsql.Update<ProductSku>().Set(p => p.State, 4).Where(p => goneProductSkuIdList.Contains(p.Id));
                    updateProductSkuList.Add(update);
                }
                #endregion


                fsql.Transaction(() =>
                {
                    if (insertProductList.Count() > 0)
                        fsql.Insert(insertProductList).ExecuteAffrows();
                    if (insertProductSkuList.Count() > 0)
                        fsql.Insert(insertProductSkuList).ExecuteAffrows();

                    if (updateProductList.Count() > 0)
                    {
                        foreach (var update in updateProductList)
                            update.ExecuteAffrows();
                    }

                    if (updateProductSkuList.Count() > 0)
                    {
                        foreach (var update in updateProductSkuList)
                            update.ExecuteAffrows();
                    }
                });
            }
            catch (Exception ex)
            {
                var shopData = JsonConvert.SerializeObject(shop);
                nLogManager.Default().Error(ex, $"SyncProduct ShopData:{shopData}");
            }
        }

        /// <summary>
        /// 同步所有店铺的前50个产品
        /// </summary>
        public void SyncAllShopProduct()
        {
            var shopList = venderBusiness.GetShopList(platform: Enums.Platform.京东);
            //SyncProduct(shopList.FirstOrDefault(s => s.ShopId == "12657364"), true); //布莱特玩具专营店
            foreach (var shop in shopList)
            {
                Task.Factory.StartNew(() => SyncProduct(shop), System.Threading.CancellationToken.None, TaskCreationOptions.LongRunning, taskSchedulerManager.ProductSyncTaskScheduler);
            }
        }

        /// <summary>
        /// 同步所有店铺的全部产品
        /// </summary>
        public void SyncAllShopAllProduct()
        {
            var shopList = venderBusiness.GetShopList(platform: Enums.Platform.京东);
            //SyncProduct(shopList.FirstOrDefault(s => s.ShopName == "披风熊玩具专营店"), true);
            foreach (var shop in shopList)
            {
                Task.Factory.StartNew(() => SyncProduct(shop, true), CancellationToken.None, TaskCreationOptions.LongRunning, taskSchedulerManager.ProductSyncTaskScheduler);
            }
        }

        private string GetCategoryName(ShopResponse shop, string categoryId)
        {
            if (categoryCache.TryGetValue(categoryId, out string name))
                return name;
            try
            {
                var res = productBusiness.GetCategoyrInfo(new JDQueryCategoryRequest()
                {
                    AppKey = shop.AppKey,
                    CategoryId = categoryId,
                    AppSecret = shop.AppSecret,
                    AppToken = shop.AppToken,
                    Platform = shop.PlatformId
                });
                categoryCache.TryAdd(categoryId, res.Name);
                name = res.Name;
            }
            catch
            {

            }
            return name;
        }
    }
}