using Bp.Sync.BackEnd.Infrastructure.Repositories;
using Bp.Sync.Domain.Elastics.Inventories;
using Bp.Sync.Domain.Entities.Inventories.Orders;
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.Orders
{
    public class SyncOrderHandler : IRequestHandler<SyncOrderCommand, Dto.Results.BaseResult>
    {
        private readonly IDbConnection _dbConnection;
        private readonly IOrderRepository _OrderRepository;
        private readonly IBillRepository _billRepository;
        private readonly IBus _bus;

        public SyncOrderHandler(IConfiguration configuration, IOrderRepository OrderRepository, IBillRepository billRepository, IBus bus)
        {
            var connectionString = configuration.GetConnectionString("InventoryConnection");
            _dbConnection = new SqlConnection(connectionString);
            _OrderRepository = OrderRepository;
            _billRepository = billRepository;
            _bus = bus;
        }

        public async Task<Dto.Results.BaseResult> Handle(SyncOrderCommand request, CancellationToken cancellationToken)
        {
            var rs = new Dto.Results.BaseResult();

            if (request.Ids.Count() > 1000)
            {
                var length = request.Ids.Count();
                if (length > 0)
                {
                    for (int i = 0; i <= length / 1000; i++)
                    {
                        if (length > i * 1000)
                        {
                            var ids = request.Ids.Skip(i * 1000).Take(1000).ToList();
                            if (ids.Count() > 0)
                            {
                                await _bus.SendAsync($"SyncToElasticOrder0", ids.ConvertListLongToString());
                            }
                        }
                    }
                }
                return new BaseResult { Result = Dto.Results.Result.Success, Message = $"sent {length} Orders" };
            }

            try
            {
                if (!request.Ids.Any())
                {
                    rs.Message = $"no data to update";
                    rs.Result = Dto.Results.Result.Success;
                    return rs;
                }
                var p = new Dto.DapperTypes.IdsParam(request.Ids);
                var Orders = await _dbConnection.QueryAsync<Order>("Sync_Order_Get_By_List_Id", p, commandType: CommandType.StoredProcedure);
                if (Orders.Any())
                {
                    var OrderRs = Orders.ToOrders();

                    //thêm trạng thái thu tiền trong phiếu xuất
                    if (OrderRs.Any())
                    {
                        var codes = OrderRs.Select(x => x.Code).ToList();
                        var query = new Nest.BoolQueryDescriptor<BillElastic>();
                        var codeQ = new Nest.QueryContainerDescriptor<BillElastic>();
                        codeQ.Terms(t => t.Field(f => f.OrderCode.Suffix("keyword")).Terms(codes));
                        var isDeletedQ = new Nest.QueryContainerDescriptor<BillElastic>();
                        isDeletedQ.Terms(e => e.Field(f => f.IsDeleted).Terms(false));
                        query.Filter(f => codeQ && isDeletedQ);
                        var bills = await _billRepository.Search(query, 10000);
                        if (bills.Items.Any())
                        {
                            foreach (var item in OrderRs)
                            {
                                var bill = bills.Items.FirstOrDefault(x => x.OrderCode == item.Code);
                                if (bill != null)
                                {
                                    item.BillCollectMoneyStatus = bill.CollectMoneyStatus;
                                    item.BillCompletedTime = bill.CompletedTime;
                                }
                            }
                        }
                    }

                    var rs2 = await _OrderRepository.AddManyAsync(OrderRs);
                    if (rs2.Result == Dto.Results.Result.Success)
                    {
                        await _dbConnection.ExecuteAsync("Synced_Order_By_List_Id", p, commandType: CommandType.StoredProcedure);

                        await _bus.SendAsync($"SyncToElasticProductOrderByOrder", request.Ids.ConvertListLongToString());

                        rs.Message = $"{OrderRs.Count()} synced";
                        rs.Result = Dto.Results.Result.Success;
                    }
                    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;
        }
    }
}