using Bp.Inventory.Domain.Batches;
using Bp.Sync.BackEnd.Infrastructure.Repositories;
using Bp.Sync.BackEnd.Infrastructure.Repositories.FcBusinesses;
using Bp.Sync.Domain.Elastics.FcBusinesses.Products;
using Bp.Sync.Domain.Elastics.Inventories;
using Bp.Sync.Domain.Elastics.Inventories.Products;
using Bp.Sync.Dto.Results;
using CommonLibrary;
using Dapper;
using EasyNetQ;
using MediatR;
using Microsoft.Extensions.Configuration;
using Nest;
using System;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Vina.Search.Infrastructure.Mappings;

namespace Bp.Sync.BackEnd.Application.Commands.Inventories.Batches
{
    public class SyncBatchHandler : IRequestHandler<SyncBatchCommand, BaseResult>
    {
        private readonly IDbConnection _dbConnection;
        private readonly IBatchRepository _BatchRepository;
        private readonly IProductInventoryRepository _productInventoryRepository;
        private readonly IFcProductStorageRepository _FcProductStorageRepository;
        private readonly IBus _bus;

        public SyncBatchHandler(IConfiguration configuration, IBatchRepository BatchRepository, IBus bus, IProductInventoryRepository productInventoryRepository,
            IFcProductStorageRepository FcProductStorageRepository)
        {
            var connectionString = configuration.GetConnectionString("InventoryConnection");
            _dbConnection = new SqlConnection(connectionString);
            _BatchRepository = BatchRepository;
            _productInventoryRepository = productInventoryRepository;
            _bus = bus;
            _FcProductStorageRepository = FcProductStorageRepository;
        }

        public async Task<BaseResult> Handle(SyncBatchCommand request, CancellationToken cancellationToken)
        {
            var rs = new BaseResult();

            if (request.Ids.Count() > 1000)
            {
                var length = request.Ids.Count();
                if (length > 0)
                {
                    for (int i = 0; i <= length / 100; i++)
                    {
                        if (length > i * 100)
                        {
                            var ids = request.Ids.Skip(i * 100).Take(100).ToList();
                            if (ids.Count() > 0)
                            {
                                await _bus.SendAsync($"SyncToElasticBatch", ids.ConvertListLongToString());
                            }
                        }
                    }
                }
                return new BaseResult { Result = Dto.Results.Result.Success, Message = $"sent {length} orders" };
            }
            if (!request.Ids.Any())
            {
                rs.Message = $"no data to update";
                rs.Result = Dto.Results.Result.Success;
                return rs;
            }

            try
            {
                var p = new Dto.DapperTypes.IdsParam(request.Ids);
                var Batchs = await _dbConnection.QueryAsync<Batch>("Sync_Batch_Get_By_List_Id", p, commandType: CommandType.StoredProcedure);
                if (Batchs.Any())
                {
                    var BatchRs = Batchs.ToBatches();
                    var rs2 = await _BatchRepository.AddManyAsync(BatchRs);
                    if (rs2.Result == Dto.Results.Result.Success)
                    {
                        await _dbConnection.ExecuteAsync("Synced_Batch_By_List_Id", p, commandType: CommandType.StoredProcedure);
                        rs.Message = $"{BatchRs.Count()} synced";
                        rs.Result = Dto.Results.Result.Success;

                        //lấy ra danh sách lưu kho để cập nhật ngày hạn

                        var inventoryCodes = BatchRs.Where(x => !string.IsNullOrEmpty(x.InventoryCode) && !string.IsNullOrWhiteSpace(x.InventoryCode)).Select(x => x.InventoryCode).Distinct().ToList();
                        var inventoryCodeQ = new QueryContainerDescriptor<ProductInventoryElastic>();
                        if (inventoryCodes.Any())
                            inventoryCodeQ.Terms(e => e.Field(f => f.InventoryCode.Suffix("keyword")).Terms(inventoryCodes));
                        var productIds = BatchRs.Select(x => x.ProductId).Distinct().ToList();
                        var productInQ = new QueryContainerDescriptor<ProductInventoryElastic>();
                        if (productIds.Any())
                            productInQ.Terms(e => e.Field(f => f.ProductId).Terms(productIds));
                        var notDeleteQ = new QueryContainerDescriptor<ProductInventoryElastic>();
                        notDeleteQ.Terms(t => t.Field(f => f.IsDeleted).Terms(false));
                        var query = new BoolQueryDescriptor<ProductInventoryElastic>();
                        query.Filter(f => inventoryCodeQ && productInQ && notDeleteQ);
                        var ins = await _productInventoryRepository.Search(query, 10000);
                        if (ins.Items.Any())
                        {
                            var piIds = ins.Items.Select(x => x.Id).ToList();
                            await _bus.SendAsync($"UpdateToElasticProductInventoryEx", piIds.ConvertListLongToString());
                        }

                        //lay danh sach luu kho o chi nhanh
                        var queryBranch = new BoolQueryDescriptor<FcProductStorageElastic>();
                        var inventoryCodeFcQ = new QueryContainerDescriptor<FcProductStorageElastic>();
                        if (inventoryCodes.Any())
                            inventoryCodeFcQ.Terms(e => e.Field(f => f.InventoryCode.Suffix("keyword")).Terms(inventoryCodes));
                        var notDeleteFcQ = new QueryContainerDescriptor<FcProductStorageElastic>();
                        notDeleteFcQ.Terms(t => t.Field(f => f.IsDeleted).Terms(false));
                        var productInFcQ = new QueryContainerDescriptor<FcProductStorageElastic>();
                        if (productIds.Any())
                            productInFcQ.Terms(e => e.Field(f => f.ProductId).Terms(productIds));
                        queryBranch.Filter(f => inventoryCodeFcQ && productInFcQ && notDeleteFcQ);

                        var inBrs = await _FcProductStorageRepository.Search(queryBranch, 10000);
                        if (inBrs.Items.Any())
                        {
                            var piIds = inBrs.Items.Select(x => x.Id).ToList();
                            await _bus.SendAsync($"UpdateFcProductStorage", piIds.ConvertListLongToString());
                        }
                    }
                    else
                    {
                        rs.Message = $"can not insert db";
                        rs.Result = Dto.Results.Result.Success;
                    }
                }
                else
                {
                    rs.Message = $"no data to update";
                    rs.Result = Dto.Results.Result.Success;
                }
            }
            catch (Exception ex)
            {
                rs.Message = ex.Message.ToString();
                rs.Result = Dto.Results.Result.SystemError;
            }
            return rs;
        }
    }
}