using Bp.Sync.BackEnd.Infrastructure.Repositories;
using Bp.Sync.Domain.Elastics.Inventories.Categories;
using Bp.Sync.Dto.Results;
using CommonLibrary;
using Dapper;
using EasyNetQ;
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;

namespace Bp.Sync.BackEnd.Application.Commands.Inventories.Categories
{
    public class SyncCategoryHandler : MediatR.IRequestHandler<SyncCategoryCommand, BaseResult>
    {
        private readonly IDbConnection _dbConnection;
        private readonly ICategoryRepository _categoryRepository;
        private readonly IBus _bus;

        public SyncCategoryHandler(IConfiguration configuration, ICategoryRepository categoryRepository, IBus bus)
        {
            var connectionString = configuration.GetConnectionString("InventoryConnection");
            _dbConnection = new SqlConnection(connectionString);
            _categoryRepository = categoryRepository;
            _bus = bus;
        }

        public async Task<BaseResult> Handle(SyncCategoryCommand 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($"SyncToElasticCategory", ids.ConvertListLongToString());
                            }
                        }
                    }
                }
                return new BaseResult { Result = Result.Success, Message = $"sent {length} Categorys" };
            }
            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 entities = await _dbConnection.QueryAsync<CategoryElastic>("Sync_Category_Get_By_List_Id", p, commandType: CommandType.StoredProcedure);
                if (entities.Any())
                {
                    var list = new List<CategoryElastic>();
                    var areaIds = entities.Where(x => x.AreaId.HasValue).Select(x => (long)x.AreaId.Value).Distinct().ToList();
                    var cityIds = entities.Where(x => x.CityId > 0).Select(x => (long)x.CityId).Distinct().ToList();
                    var districtIds = entities.Where(x => x.DistrictId > 0).Select(x => (long)x.DistrictId).Distinct().ToList();

                    var listIds = new List<long>();
                    if (areaIds.Any()) listIds.AddRange(areaIds);
                    if (cityIds.Any()) listIds.AddRange(cityIds);
                    if (districtIds.Any()) listIds.AddRange(districtIds);
                    if (listIds.Any())
                    {
                        list = list.Select(x => x).Distinct().ToList();
                        var p2 = new Dto.DapperTypes.IdsParam(listIds);
                        var list2 = await _dbConnection.QueryAsync<CategoryElastic>("Sync_Category_Get_By_List_Id", p2, commandType: CommandType.StoredProcedure);
                        if (list2.Any())
                            list = list2.ToList();
                    }
                    foreach (var item in entities)
                    {
                        if (item.AreaId.HasValue)
                        {
                            var area = list.FirstOrDefault(x => x.Id == item.AreaId.Value);
                            if (area != null)
                            {
                                item.AreaName = area.Name;
                                item.Region = area.Region;
                            }
                        }
                        if (item.Discriminator == "District" && item.CityId > 0)
                        {
                            var city = list.FirstOrDefault(x => x.Id == item.CityId);
                            if (city != null)
                            {
                                item.CityName = city.Name;
                                if (city.AreaId.HasValue)
                                {
                                    var area = list.FirstOrDefault(x => x.Id == city.AreaId.Value);
                                    if (area != null)
                                    {
                                        item.AreaId = (int)area.Id;
                                        item.AreaName = area.Name;
                                        item.Region = area.Region;
                                    }
                                }
                            }
                        }
                        if (item.Discriminator == "Ward" && item.DistrictId > 0)
                        {
                            var district = list.FirstOrDefault(x => x.Id == item.DistrictId);
                            if (district != null)
                            {
                                item.DistrictName = district.Name;
                                item.IsUrban = district.IsUrban;
                                var city = list.FirstOrDefault(x => x.Id == district.CityId);
                                if (city != null)
                                {
                                    item.CityId = (int)city.Id;
                                    item.CityName = city.Name;
                                    if (city.AreaId.HasValue)
                                    {
                                        var area = list.FirstOrDefault(x => x.Id == city.AreaId.Value);
                                        if (area != null)
                                        {
                                            item.AreaId = (int)area.Id;
                                            item.AreaName = area.Name;
                                            item.Region = area.Region;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    var rs2 = await _categoryRepository.AddManyAsync(entities);
                    if (rs2.Result == Result.Success)
                    {
                        await _dbConnection.ExecuteAsync("Synced_Category_By_List_Id", p, commandType: CommandType.StoredProcedure);
                        rs.Message = $"{entities.Count()} synced";
                        rs.Result = Result.Success;
                    }
                    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;
        }
    }
}