using Bp.Sync.BackEnd.Infrastructure.Repositories;
using Bp.Sync.Domain.Entities.Inventories.Orders;
using Bp.Sync.Domain.Entities.Inventories.Reasons;
using Bp.Sync.Dto.Results;
using CommonLibrary;
using Dapper;
using EasyNetQ;
using MediatR;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
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.ProductOrders
{
    public class SyncProductOrderHandler : IRequestHandler<SyncProductOrderCommand, BaseResult>
    {
        private readonly IDbConnection _dbConnection;
        private readonly IProductOrderRepository _ProductOrderRepository;
        private readonly IOrderRepository _orderRepository;

        private readonly IBus _bus;

        public SyncProductOrderHandler(IConfiguration configuration, IProductOrderRepository ProductOrderRepository, IOrderRepository orderRepository, IBus bus)
        {
            var connectionString = configuration.GetConnectionString("InventoryConnection");
            _dbConnection = new SqlConnection(connectionString);
            _ProductOrderRepository = ProductOrderRepository;
            _orderRepository = orderRepository;
            _bus = bus;
        }

        public async Task<BaseResult> Handle(SyncProductOrderCommand 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 / 1000; i++)
                    {
                        if (length > i * 1000)
                        {
                            var ids = request.Ids.Skip(i * 1000).Take(1000).ToList();
                            if (ids.Count() > 0)
                            {
                                await _bus.SendAsync($"SyncToElasticProductOrder0", ids.ConvertListLongToString());
                            }
                        }
                    }
                }
                return new BaseResult { Result = Result.Success, Message = $"sent {length} ProductOrders" };
            }

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

            try
            {
                if (request.Ids.Any())
                {
                    var p = new Dto.DapperTypes.IdsParam(request.Ids);
                    var ProductOrders = await _dbConnection.QueryAsync<ProductOrder>("Sync_ProductOrder_Get_By_List_Id", p, commandType: CommandType.StoredProcedure);
                    if (ProductOrders.Any())
                    {
                        var ProductOrderRs = ProductOrders.ToProductOrders();

                        //lấy ra trạng thái của đưn hàng
                        var orderids = ProductOrderRs.Select(x => x.OrderId).Distinct().ToList();
                        var p2 = new Dto.DapperTypes.IdsParam(orderids);
                        var Orders = await _dbConnection.QueryAsync<Order>("Sync_Order_Get_By_List_Id", p2, commandType: CommandType.StoredProcedure);

                        var orderelastics = await _orderRepository.GetByIds(orderids);

                        var reasons = new List<Reason>();
                        var reasonids = ProductOrderRs.Select(x => (long)x.ReasonId).Distinct().ToList();
                        var pReason = new Dto.DapperTypes.IdsParam(reasonids);
                        var reasons2 = await _dbConnection.QueryAsync<Reason>("Sync_Reason_Get_By_List_Id", pReason, commandType: CommandType.StoredProcedure);

                        if (Orders.Any())
                        {
                            foreach (var item in ProductOrderRs)
                            {
                                var or = Orders.FirstOrDefault(x => x.Id == item.OrderId);
                                if (or != null)
                                {
                                    item.OrderIsDeleted = or.IsDeleted;
                                    item.OrderType = or.OrderType;
                                    item.OrderStatus = or.OrderStatus;
                                    item.OrderCode = or.Code;
                                    item.OrderBranchId = or.BranchId;
                                    item.OrderDestBranchId = or.DestBranchId;
                                    item.OrderCustomerId = or.CustomerId;
                                    item.OrderCreatedBy = or.CreatedBy;
                                    item.OrderCreatedByUserName = or.CreatedByUserName;
                                    item.OrderCreatedTime = or.CreatedTime;
                                    item.OrderApprovedDate = or.ApprovedDate;
                                    item.OrderDate = or.OrderDate;
                                    item.OrderSlaTime = or.SlaTime;
                                }
                                var orelastic = orderelastics.Items.FirstOrDefault(x => x.Id == item.OrderId);
                                if (orelastic != null)
                                {
                                    item.BillCollectMoneyStatus = orelastic.BillCollectMoneyStatus;
                                    item.BillCompletedTime = orelastic.BillCompletedTime;
                                }
                                if (item.ReasonId > 0)
                                {
                                    var re = reasons.FirstOrDefault(x => x.Id == item.ReasonId);
                                    if (re != null)
                                    {
                                        item.ReasonIsReject = re.IsReject;
                                        item.ReasonName = re.Name;
                                        item.ReasonType = re.ReasonType;
                                    }
                                }
                            }
                        }
                        var rs2 = await _ProductOrderRepository.AddManyAsync(ProductOrderRs);
                        if (rs2.Result == Result.Success)
                        {
                            await _dbConnection.ExecuteAsync("Synced_ProductOrder_By_List_Id", p, commandType: CommandType.StoredProcedure);
                            rs.Message = $"{ProductOrderRs.Count()} synced";
                            rs.Result = Result.Success;
                            _bus.SendAsync($"UpdateToElasticProductOrder", ProductOrderRs.Select(x => x.Id).ToList().ConvertListLongToString());
                        }
                        else
                        {
                            rs.Message = $"can not insert db";
                            rs.Result = Result.Success;
                        }
                    }
                    else
                    {
                        rs.Message = $"no data to update";
                        rs.Result = Result.Success;
                    }
                }

                if (request.OrderIds.Any())
                {
                    var p = new Dto.DapperTypes.IdsParam(request.OrderIds);
                    var ProductOrders = await _dbConnection.QueryAsync<ProductOrder>("Sync_ProductOrder_Get_By_List_OrderId", p, commandType: CommandType.StoredProcedure);
                    if (ProductOrders.Any())
                    {
                        var ProductOrderRs = ProductOrders.ToProductOrders();

                        //lấy ra trạng thái của đưn hàng
                        var orderids = ProductOrderRs.Select(x => x.OrderId).Distinct().ToList();
                        var p2 = new Dto.DapperTypes.IdsParam(orderids);
                        var Orders = await _dbConnection.QueryAsync<Order>("Sync_Order_Get_By_List_Id", p2, commandType: CommandType.StoredProcedure);
                        var orderelastics = await _orderRepository.GetByIds(orderids);

                        var reasonids = ProductOrderRs.Select(x => (long)x.ReasonId).Distinct().ToList();
                        var pReason = new Dto.DapperTypes.IdsParam(reasonids);
                        var reasons = await _dbConnection.QueryAsync<Reason>("Sync_Reason_Get_By_List_Id", pReason, commandType: CommandType.StoredProcedure);

                        if (Orders.Any())
                        {
                            foreach (var item in ProductOrderRs)
                            {
                                var or = Orders.FirstOrDefault(x => x.Id == item.OrderId);
                                if (or != null)
                                {
                                    item.OrderIsDeleted = or.IsDeleted;
                                    item.OrderType = or.OrderType;
                                    item.OrderStatus = or.OrderStatus;
                                    item.OrderCode = or.Code;
                                    item.OrderBranchId = or.BranchId;
                                    item.OrderDestBranchId = or.DestBranchId;
                                    item.OrderCustomerId = or.CustomerId;
                                    item.OrderCreatedBy = or.CreatedBy;
                                    item.OrderCreatedByUserName = or.CreatedByUserName;
                                    item.OrderCreatedTime = or.CreatedTime;
                                    item.OrderApprovedDate = or.ApprovedDate;
                                    item.OrderDate = or.OrderDate;
                                    item.OrderSlaTime = or.SlaTime;
                                }

                                var orelastic = orderelastics.Items.FirstOrDefault(x => x.Id == item.OrderId);
                                if (orelastic != null)
                                {
                                    item.BillCollectMoneyStatus = orelastic.BillCollectMoneyStatus;
                                    item.BillCompletedTime = orelastic.BillCompletedTime;
                                }
                                if (item.ReasonId > 0)
                                {
                                    var re = reasons.FirstOrDefault(x => x.Id == item.ReasonId);
                                    if (re != null)
                                    {
                                        item.ReasonIsReject = re.IsReject;
                                        item.ReasonName = re.Name;
                                        item.ReasonType = re.ReasonType;
                                    }
                                }
                            }
                        }
                        var rs2 = await _ProductOrderRepository.AddManyAsync(ProductOrderRs);
                        if (rs2.Result == Result.Success)
                        {
                            var pids = ProductOrderRs.Select(x => x.Id).ToList();
                            var p3 = new Dto.DapperTypes.IdsParam(pids);
                            await _dbConnection.ExecuteAsync("Synced_ProductOrder_By_List_Id", p3, commandType: CommandType.StoredProcedure);
                            rs.Message = $"{ProductOrderRs.Count()} synced";
                            rs.Result = Result.Success;
                            _bus.SendAsync($"UpdateToElasticProductOrder", ProductOrderRs.Select(x => x.Id).ToList().ConvertListLongToString());
                        }
                        else
                        {
                            rs.Message = $"can not insert db";
                            rs.Result = Result.Success;
                        }
                    }
                    else
                    {
                        rs.Message = $"no data to update";
                        rs.Result = Result.Success;
                    }
                }
            }
            catch (Exception ex)
            {
                rs.Message = ex.Message.ToString();
                rs.Result = Result.SystemError;
            }
            return rs;
        }
    }
}