using Bp.Sync.Dto.Results;
using CommonLibrary;
using Dapper;
using EasyNetQ;
using MediatR;
using Microsoft.Extensions.Configuration;
using System;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Vina.Search.Infrastructure.Mappings;
using Bp.Sync.BackEnd.Infrastructure.Repositories;
using Bp.Sync.Domain.Entities.Inventories.Invoices;

namespace Bp.Sync.BackEnd.Application.Commands.Inventories.ProductInvoices
{
    public class SyncProductInvoiceHandler : IRequestHandler<SyncProductInvoiceCommand, BaseResult>
    {
        private readonly IDbConnection _dbConnection;
        private readonly IProductInvoiceRepository _ProductInvoiceRepository;
        private readonly IInvoiceRepository _invoiceRepository;
        private readonly IBus _bus;

        public SyncProductInvoiceHandler(IConfiguration configuration, IProductInvoiceRepository ProductInvoiceRepository, IBus bus, IInvoiceRepository invoiceRepository)
        {
            var connectionString = configuration.GetConnectionString("InventoryConnection");
            _dbConnection = new SqlConnection(connectionString);
            _ProductInvoiceRepository = ProductInvoiceRepository;
            _invoiceRepository = invoiceRepository;
            _bus = bus;
        }

        public async Task<BaseResult> Handle(SyncProductInvoiceCommand 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($"SyncToElasticProductInvoice0", ids.ConvertListLongToString());
                            }
                        }
                    }
                }
                return new BaseResult { Result = Dto.Results.Result.Success, Message = $"sent {length} ProductInvoices" };
            }

            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 ProductInvoices = await _dbConnection.QueryAsync<ProductInvoice>("Sync_ProductInvoice_Get_By_List_Id", p, commandType: CommandType.StoredProcedure);
                if (ProductInvoices.Any())
                {
                    var items = ProductInvoices.ToProductInvoices();

                    //lấy ra invoice để cập nhât
                    var invoiceIds = items.Select(x => x.InvoiceId).Distinct().ToList();
                    var invoices = await _invoiceRepository.GetByIds(invoiceIds);
                    if (invoices.Items != null && invoices.Items.Any())
                    {
                        foreach (var item in items)
                        {
                            var invoice = invoices.Items.FirstOrDefault(x => x.Id == item.InvoiceId);
                            if (invoice != null)
                            {
                                item.InvoiceType = invoice.InvoiceType;
                                item.InvoiceBranchId = invoice.BranchId;
                                item.InvoiceCustomerId = invoice.CustomerId;
                                item.InvoiceCreatedBy = invoice.CreatedBy;
                                item.InvoiceCreatedByUserName = invoice.CreatedByUserName;
                                item.InvoiceCreatedTime = invoice.CreatedTime;
                                item.InvoiceIsDeleted = invoice.IsDeleted;
                                item.InvoiceUpdatedBy = invoice.UpdatedBy;
                                item.InvoiceUpdatedByUserName = invoice.UpdatedByUserName;
                                item.InvoiceUpdatedTime = invoice.UpdatedTime;
                            }
                        }
                    }

                    var rs2 = await _ProductInvoiceRepository.AddManyAsync(items);
                    if (rs2.Result == Result.Success)
                    {
                        await _dbConnection.ExecuteAsync("Synced_ProductInvoice_By_List_Id", p, commandType: CommandType.StoredProcedure);
                        rs.Message = $"{items.Count()} synced";
                        rs.Result = Result.Success;

                        //cập nhật dữ liệu ngay
                        if (request.Ids.Count() > 0)
                        {
                            var length = request.Ids.Count();
                            if (length > 0)
                            {
                                int j = 0;
                                for (int i = 0; i <= length / 100; i++)
                                {
                                    j++;
                                    if (length > i * 100)
                                    {
                                        var ids = request.Ids.Skip(i * 100).Take(100).ToList();
                                        if (ids.Count() > 0)
                                        {
                                            await _bus.SendAsync($"UpdateElasticProductInventory{j}", ids.ConvertListLongToString());
                                        }
                                    }
                                    if (j > 4) j = 0;
                                }
                            }
                        }
                    }
                    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;
        }
    }
}