using Bp.Sync.Dto.Results;
using EasyNetQ;
using MediatR;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Bp.Sync.BackEnd.Infrastructure.Repositories;
using Bp.Sync.Domain.Elastics.Inventories;
using Nest;
using Bp.Sync.Domain.Elastics.DailyTasks;
using System.Collections.Generic;
using Bp.Sync.Domain.Elastics.Inventories.Products;
using Bp.Sync.BackEnd.Infrastructure.Repositories.FcBusinesses;
using Bp.Sync.Domain.Elastics.FcBusinesses.Products;
using Bp.Sync.BackEnd.Infrastructure.Repositories.DailyInventoryDiarys;
using Bp.Sync.Domain.Elastics.Inventories.Categories;

namespace Bp.Sync.BackEnd.Application.Commands.DailyTasks.InventoryDiaries
{
    public class AddDailyTaskHandler : IRequestHandler<AddDailyTaskCommand, BaseResult>
    {
        private readonly IBranchRepository _branchRepository;
        private readonly IProductInventoryRepository _productInventoryRepository;
        private readonly IFcProductStorageRepository _fcProductStorageRepository;
        private readonly IBus _bus;
        private readonly IDailyInventoryDiaryRepository _dailyInventoryDiaryRepository;
        private readonly IWholesalePriceListRepository _wholesalePriceListRepository;

        public AddDailyTaskHandler(IBranchRepository branchRepository, IProductInventoryRepository productInventoryRepository,
            IWholesalePriceListRepository wholesalePriceListRepository,
            IFcProductStorageRepository fcProductStorageRepository, IBus bus, IDailyInventoryDiaryRepository dailyInventoryDiaryRepository)
        {
            _branchRepository = branchRepository;
            _productInventoryRepository = productInventoryRepository;
            _fcProductStorageRepository = fcProductStorageRepository;
            _dailyInventoryDiaryRepository = dailyInventoryDiaryRepository;
            _wholesalePriceListRepository = wholesalePriceListRepository;
            _bus = bus;
        }

        public async Task<BaseResult> Handle(AddDailyTaskCommand request, CancellationToken cancellationToken)
        {
            var result = new BaseResult();
            var today = DateTimeOffset.Now.AddMinutes(1).AddDays(-1);
            var timeNow = new DateTimeOffset(today.Year, today.Month, today.Day, 23, 59, 59, new TimeSpan(7, 0, 0));
            //lay danh sach chi nhanh

            var isDeletedBranchQ = new QueryContainerDescriptor<BranchElastic>();
            isDeletedBranchQ.Terms(t => t.Field(f => f.IsDeleted).Terms(false));
            var query = new BoolQueryDescriptor<BranchElastic>();
            query.Filter(isDeletedBranchQ);
            var bs = await _branchRepository.Search(query);
            var branches = bs.Items;

            var dmy = $"{timeNow:yyMMdd}";

            var list = new List<InventoryDiaryElastic>();
            foreach (var item in branches)
            {
                var stack3 = "000000";
                if (item.Id.ToString().Length >= 6) stack3 = item.Id.ToString();
                else stack3 = stack3.Substring(0, 6 - item.Id.ToString().Length) + item.Id;

                stack3 = dmy + stack3;
                var l = new InventoryDiaryElastic
                {
                    Id = long.Parse(stack3),
                    BranchId = item.Id,
                    BranchName = item.Name,
                    CreatedTime = timeNow,
                    UpdatedTime = timeNow
                };
                list.Add(l);
            }
            //ban buon
            var queryWP = new BoolQueryDescriptor<WholesalePriceListElastic>();

            var isDeletedQWP = new QueryContainerDescriptor<WholesalePriceListElastic>();
            isDeletedQWP.Terms(t => t.Field(f => f.IsDeleted).Terms(false));

            queryWP.Filter(fl => isDeletedQWP);

            var wholesalePriceLists = await _wholesalePriceListRepository.Search(queryWP);
            var wholesalePriceListIds = wholesalePriceLists.Items.Select(x => x.ProductId).Distinct().ToList();
            //lay tong so san pham ton kho

            #region SC

            var queryPI = new BoolQueryDescriptor<ProductInventoryElastic>();
            var aggsPI = new AggregationContainerDescriptor<ProductInventoryElastic>();

            var quatityThan0PIQ = new QueryContainerDescriptor<ProductInventoryElastic>();
            quatityThan0PIQ.Range(r => r.Field(f => f.Quantity).GreaterThan(0));
            var productIdThan0PIQ = new QueryContainerDescriptor<ProductInventoryElastic>();
            productIdThan0PIQ.Range(r => r.Field(f => f.ProductId).GreaterThan(0));
            var isDeletedPIQ = new QueryContainerDescriptor<ProductInventoryElastic>();
            isDeletedPIQ.Terms(t => t.Field(f => f.IsDeleted).Terms(false));
            queryPI.Filter(f => quatityThan0PIQ && productIdThan0PIQ && isDeletedPIQ);
            aggsPI.Terms("branch", t => t.Field(f => f.BranchId).Size(10000).Aggregations(a2 => a2.Cardinality("product", s2 => s2.Field(f2 => f2.ProductId))));
            var rsPI = await _productInventoryRepository.SearchAgg(queryPI, aggsPI);
            var aggPI = rsPI.Aggregations.Terms("branch");
            if (aggPI != null)
            {
                foreach (var item in aggPI.Buckets)
                {
                    var ProductInventory = list.FirstOrDefault(x => x.BranchId == long.Parse(item.Key));
                    if (item.DocCount.HasValue && ProductInventory != null)
                    {
                        var agg2 = item.Cardinality("product");
                        if (agg2 != null)
                        {
                            ProductInventory.NumberOfProduct += (long)agg2.Value.Value;
                        }
                    }
                }
            }
            aggsPI.Terms("branch", t => t.Field(f => f.BranchId).Size(10000).Aggregations(a2 => a2.Sum("quantity", s2 => s2.Field(f2 => f2.Quantity))));
            rsPI = await _productInventoryRepository.SearchAgg(queryPI, aggsPI);
            aggPI = rsPI.Aggregations.Terms("branch");
            if (aggPI != null)
            {
                foreach (var item in aggPI.Buckets)
                {
                    var ProductInventory = list.FirstOrDefault(x => x.BranchId == long.Parse(item.Key));
                    if (item.DocCount.HasValue && ProductInventory != null)
                    {
                        var agg2 = item.Sum("quantity");
                        if (agg2 != null)
                        {
                            ProductInventory.BaseUnitQuantity += (decimal)agg2.Value.Value;
                        }
                    }
                }
            }
            aggsPI.Terms("branch", t => t.Field(f => f.BranchId).Size(10000).Aggregations(a2 => a2.Sum("amount", s2 => s2.Field(f2 => f2.Amount))));
            rsPI = await _productInventoryRepository.SearchAgg(queryPI, aggsPI);
            aggPI = rsPI.Aggregations.Terms("branch");
            if (aggPI != null)
            {
                foreach (var item in aggPI.Buckets)
                {
                    var ProductInventory = list.FirstOrDefault(x => x.BranchId == long.Parse(item.Key));
                    if (item.DocCount.HasValue && ProductInventory != null)
                    {
                        var agg2 = item.Sum("amount");
                        if (agg2 != null)
                        {
                            ProductInventory.PriceAmount += (decimal)agg2.Value.Value;
                        }
                    }
                }
            }

            aggsPI.Terms("branch", t => t.Field(f => f.BranchId).Size(10000).Aggregations(a2 => a2.Sum("billprice", s2 => s2.Field(f2 => f2.ProductBillPrice))));
            rsPI = await _productInventoryRepository.SearchAgg(queryPI, aggsPI);
            aggPI = rsPI.Aggregations.Terms("branch");
            if (aggPI != null)
            {
                foreach (var item in aggPI.Buckets)
                {
                    var ProductInventory = list.FirstOrDefault(x => x.BranchId == long.Parse(item.Key));
                    if (item.DocCount.HasValue && ProductInventory != null)
                    {
                        var agg2 = item.Sum("billprice");
                        if (agg2 != null)
                        {
                            ProductInventory.CostAmount += (decimal)agg2.Value.Value;
                        }
                    }
                }
            }
            //ton ban buon

            if (wholesalePriceListIds.Any())
            {
                var wholesalePriceListPIQ = new QueryContainerDescriptor<ProductInventoryElastic>();
                wholesalePriceListPIQ.Terms(r => r.Field(f => f.ProductId).Terms(wholesalePriceListIds));
                queryPI.Filter(f => quatityThan0PIQ && productIdThan0PIQ && isDeletedPIQ && wholesalePriceListPIQ);
                aggsPI.Terms("branch", t => t.Field(f => f.BranchId).Size(10000).Aggregations(a2 => a2.Sum("billprice", s2 => s2.Field(f2 => f2.ProductBillPrice))));
                rsPI = await _productInventoryRepository.SearchAgg(queryPI, aggsPI);
                aggPI = rsPI.Aggregations.Terms("branch");
                if (aggPI != null)
                {
                    foreach (var item in aggPI.Buckets)
                    {
                        var ProductInventory = list.FirstOrDefault(x => x.BranchId == long.Parse(item.Key));
                        if (item.DocCount.HasValue && ProductInventory != null)
                        {
                            var agg2 = item.Sum("billprice");
                            if (agg2 != null)
                            {
                                ProductInventory.CostWholesaleAmount += (decimal)agg2.Value.Value;
                            }
                        }
                    }
                }
            }

            #endregion SC

            #region FC

            var queryFC = new BoolQueryDescriptor<FcProductStorageElastic>();
            var aggsFC = new AggregationContainerDescriptor<FcProductStorageElastic>();
            var quatityThan0FCQ = new QueryContainerDescriptor<FcProductStorageElastic>();
            quatityThan0FCQ.Range(r => r.Field(f => f.CurrentQuantity).GreaterThan(0));
            var productIdThan0FCQ = new QueryContainerDescriptor<FcProductStorageElastic>();
            productIdThan0FCQ.Range(r => r.Field(f => f.ProductId).GreaterThan(0));
            var isDeletedFCQ = new QueryContainerDescriptor<FcProductStorageElastic>();
            isDeletedFCQ.Terms(t => t.Field(f => f.IsDeleted).Terms(false));
            queryFC.Filter(f => quatityThan0FCQ && productIdThan0FCQ && isDeletedFCQ);

            aggsFC.Terms("branch", t => t.Field(f => f.BranchId).Size(10000).Aggregations(a2 => a2.Cardinality("product", s2 => s2.Field(f2 => f2.ProductId))));
            var rsFC = await _fcProductStorageRepository.SearchAgg(queryFC, aggsFC);
            var aggFC = rsFC.Aggregations.Terms("branch");
            if (aggFC != null)
            {
                foreach (var item in aggFC.Buckets)
                {
                    var pr = list.FirstOrDefault(x => x.BranchId == long.Parse(item.Key));
                    if (item.DocCount.HasValue && pr != null)
                    {
                        var agg2 = item.Cardinality("product");
                        if (agg2 != null)
                        {
                            pr.NumberOfProduct += (long)agg2.Value.Value;
                        }
                    }
                }
            }

            aggsFC.Terms("branch", t => t.Field(f => f.BranchId).Size(10000).Aggregations(a2 => a2.Sum("quantity", s2 => s2.Field(f2 => f2.CurrentQuantity))));
            rsFC = await _fcProductStorageRepository.SearchAgg(queryFC, aggsFC);
            aggFC = rsFC.Aggregations.Terms("branch");
            if (aggFC != null)
            {
                foreach (var item in aggFC.Buckets)
                {
                    var pr = list.FirstOrDefault(x => x.BranchId == long.Parse(item.Key));
                    if (item.DocCount.HasValue && pr != null)
                    {
                        var agg2 = item.Sum("quantity");
                        if (agg2 != null)
                        {
                            pr.BaseUnitQuantity += (decimal)agg2.Value.Value;
                        }
                    }
                }
            }
            aggsFC.Terms("branch", t => t.Field(f => f.BranchId).Size(10000).Aggregations(a2 => a2.Sum("price", s2 => s2.Field(f2 => f2.TotalPrice))));
            rsFC = await _fcProductStorageRepository.SearchAgg(queryFC, aggsFC);
            aggFC = rsFC.Aggregations.Terms("branch");
            if (aggFC != null)
            {
                foreach (var item in aggFC.Buckets)
                {
                    var pr = list.FirstOrDefault(x => x.BranchId == long.Parse(item.Key));
                    if (item.DocCount.HasValue && pr != null)
                    {
                        var agg2 = item.Sum("price");
                        if (agg2 != null)
                        {
                            pr.PriceAmount += (decimal)agg2.Value.Value;
                        }
                    }
                }
            }
            aggsFC.Terms("branch", t => t.Field(f => f.BranchId).Size(10000).Aggregations(a2 => a2.Sum("cost", s2 => s2.Field(f2 => f2.TotalCost))));
            rsFC = await _fcProductStorageRepository.SearchAgg(queryFC, aggsFC);
            aggFC = rsFC.Aggregations.Terms("branch");
            if (aggFC != null)
            {
                foreach (var item in aggFC.Buckets)
                {
                    var pr = list.FirstOrDefault(x => x.BranchId == long.Parse(item.Key));
                    if (item.DocCount.HasValue && pr != null)
                    {
                        var agg2 = item.Sum("cost");
                        if (agg2 != null)
                        {
                            pr.CostAmount += (decimal)agg2.Value.Value;
                        }
                    }
                }
            }
            var wholesalePriceListFCQ = new QueryContainerDescriptor<FcProductStorageElastic>();
            wholesalePriceListFCQ.Terms(r => r.Field(f => f.ProductId).Terms(wholesalePriceListIds));
            queryFC.Filter(f => quatityThan0FCQ && productIdThan0FCQ && isDeletedFCQ && wholesalePriceListFCQ);
            aggsFC.Terms("branch", t => t.Field(f => f.BranchId).Size(10000).Aggregations(a2 => a2.Sum("cost", s2 => s2.Field(f2 => f2.TotalCost))));
            rsFC = await _fcProductStorageRepository.SearchAgg(queryFC, aggsFC);
            aggFC = rsFC.Aggregations.Terms("branch");
            if (aggFC != null)
            {
                foreach (var item in aggFC.Buckets)
                {
                    var pr = list.FirstOrDefault(x => x.BranchId == long.Parse(item.Key));
                    if (item.DocCount.HasValue && pr != null)
                    {
                        var agg2 = item.Sum("cost");
                        if (agg2 != null)
                        {
                            pr.CostWholesaleAmount += (decimal)agg2.Value.Value;
                        }
                    }
                }
            }

            #endregion FC

            list = list.Where(x => x.NumberOfProduct > 0).ToList();

            if (list.Any())
            {
                result = await _dailyInventoryDiaryRepository.AddManyAsync(list);
                return result;
            }

            return new BaseResult { Message = "No data", Result = Dto.Results.Result.Failed };
        }
    }
}