using Hotline.Caching.Interfaces;
using Hotline.Orders;
using Hotline.Settings;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Enums.Order;
using MapsterMapper;
using SqlSugar;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;
using XF.Domain.Repository;
using XF.Utility.SequentialId;

namespace Hotline.Application.OrderApp
{
    public class OrderAnalysisApplication : IOrderAnalysisApplication, IScopeDependency
    {
        private readonly IRepository<OrderAnalysis> _orderAnalysisRepository;
        private readonly IMapper _mapper;
        private readonly IOrderRepository _orderRepository;
        private readonly IRepository<SystemArea> _systemAreaRepository;
        private readonly ISystemSettingCacheManager _systemSettingCacheManager;

        public OrderAnalysisApplication(
            IMapper mapper,
            IOrderRepository orderRepository,
            IRepository<SystemArea> systemAreaRepository,
            IRepository<OrderAnalysis> orderAnalysisRepository,
            ISystemSettingCacheManager systemSettingCacheManager
            )
        {
            _mapper = mapper;
            _orderRepository = orderRepository;
            _orderAnalysisRepository = orderAnalysisRepository;
            _systemAreaRepository = systemAreaRepository;
            _systemSettingCacheManager = systemSettingCacheManager;
        }

        /// <summary>
        /// 新增
        /// </summary>
        /// <returns></returns>
        public async Task AddAsync(AddOrderAnalysisDto dto, CancellationToken cancellationToken)
        {
            var analysisAny = await _orderAnalysisRepository.Queryable().AnyAsync(x => x.AnalysisName == dto.AnalysisName, cancellationToken);
            if (analysisAny)
                throw UserFriendlyException.SameMessage("当前报告名称已经存在，请修改报告名称！");

            var analysisId = SequentialStringGenerator.Create();
            var generatedTime = DateTime.Now;
            var analysiss = new List<OrderAnalysis>();
            foreach (var item in dto.AnalysisList)
            {
                var analysis = _mapper.Map<OrderAnalysis>(item);
                analysis.AnalysisId = analysisId;
                analysis.AnalysisName = dto.AnalysisName;
                analysis.Remark = dto.Remark;
                analysis.GeneratedTime = generatedTime;
                analysis.StartTime = dto.StartTime;
                analysis.EndTime = dto.EndTime;
                analysiss.Add(analysis);
            }
            await _orderAnalysisRepository.AddRangeAsync(analysiss, cancellationToken);
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <returns></returns>
        public async Task UpdateAsync(UpdateOrderAnalysisDto dto, CancellationToken cancellationToken)
        {
            var analysisIdAny = await _orderAnalysisRepository.Queryable().AnyAsync(x => x.AnalysisId == dto.AnalysisId, cancellationToken);
            if (!analysisIdAny)
                throw UserFriendlyException.SameMessage("当前报告不存在，请查询报告是否已变更！");
            var analysisNameAny = await _orderAnalysisRepository.Queryable().AnyAsync(x => x.AnalysisName == dto.AnalysisName && x.AnalysisId != dto.AnalysisId, cancellationToken);
            if (analysisNameAny)
                throw UserFriendlyException.SameMessage("当前报告名称已经存在，请修改报告名称！");
            await _orderAnalysisRepository.Updateable().SetColumns(x => new OrderAnalysis { AnalysisName = dto.AnalysisName, Remark = dto.Remark })
                .Where(x => x.AnalysisId == dto.AnalysisId).ExecuteCommandAsync(cancellationToken);
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <returns></returns>
        public async Task DeleteAsync(DeleteOrderAnalysisDto dto, CancellationToken cancellationToken)
        {

            await _orderAnalysisRepository.Removeable().In(x => x.AnalysisId, dto.AnalysisIds).ExecuteCommandAsync(cancellationToken);
        }


        /// <summary>
        /// 查询列表
        /// </summary>
        /// <returns></returns>
        public ISugarQueryable<OrderAnalysisDto> ListQuery(OrderAnalysisListDto dto, CancellationToken cancellationToken)
        {
            if (dto.GeneratedEndTime.HasValue)
                dto.GeneratedEndTime = dto.GeneratedEndTime.Value.AddDays(1).AddSeconds(-1);
            var query = _orderAnalysisRepository.Queryable()
                .WhereIF(!string.IsNullOrEmpty(dto.AnalysisName), x => x.AnalysisName == dto.AnalysisName)
                .WhereIF(dto.GeneratedStartTime.HasValue && dto.GeneratedEndTime.HasValue, x => x.GeneratedTime >= dto.GeneratedStartTime && x.GeneratedTime <= dto.GeneratedEndTime)
                .GroupBy(x => new { x.AnalysisId, x.AnalysisName, x.Remark, x.GeneratedTime })
                .Select(x => new OrderAnalysisDto { AnalysisId = x.AnalysisId, AnalysisName = x.AnalysisName, Remark = x.Remark, GeneratedTime = x.GeneratedTime })
                .OrderByDescending(x => x.GeneratedTime);
            return query;
        }

        /// <summary>
        ///  查看预警事件
        /// </summary>
        /// <returns></returns>
        public ISugarQueryable<Order> DetailQuery(OrderAnalysisDetailDto dto, CancellationToken cancellationToken)
        {
            var filterTitle = _systemSettingCacheManager.GetSetting(SettingConstants.HighMatterWarningFilterTitle).SettingValue;

            var query = _orderAnalysisRepository.Queryable()
                .LeftJoin<Order>((a, o) => a.AcceptTypeCode == o.AcceptTypeCode && a.HotspotId == o.HotspotId && o.AreaCode.StartsWith(a.AreaCode))
                .Where((a, o) => a.AnalysisId == dto.AnalysisId)
                .Where((a, o) => o.CreationTime >= a.StartTime && o.CreationTime <= a.EndTime)
                .Where((a, o) => filterTitle.Any(s => o.Title.Contains(s)) == false)
                .Select((a, o) => o);
            return query;
        }

        /// <summary>
        /// 生成报告
        /// </summary>
        /// <returns></returns>
        public async Task<object> ReportQuery(OrderAnalysisDetailDto dto, CancellationToken cancellationToken)
        {
            var filterTitle = _systemSettingCacheManager.GetSetting(SettingConstants.HighMatterWarningFilterTitle).SettingValue;

            var analysis = await _orderAnalysisRepository.Queryable()
                .Where(x => x.AnalysisId == dto.AnalysisId)
                .GroupBy(x => new { x.AnalysisId, x.AnalysisName, x.GeneratedTime, x.Remark, x.StartTime, x.EndTime })
                .Select(x => new { x.AnalysisId, x.AnalysisName, x.GeneratedTime, x.Remark, x.StartTime, x.EndTime }).FirstAsync(cancellationToken);

            var orders = await _orderAnalysisRepository.Queryable()
                .LeftJoin<Order>((a, o) => a.AcceptTypeCode == o.AcceptTypeCode && a.HotspotId == o.HotspotId && o.AreaCode.StartsWith(a.AreaCode))
                .Where((a, o) => a.AnalysisId == dto.AnalysisId)
                .Where((a, o) => o.CreationTime >= a.StartTime && o.CreationTime <= a.EndTime)
                 .Where((a, o) => filterTitle.Any(s => o.Title.Contains(s)) == false)
                .Select((a, o) => o).ToListAsync(cancellationToken);
            var introductionData = orders.GroupBy(x => x.SourceChannel)
                .Select(x => new { SourceChannel = x.Key, Num = x.Count(), Rate = Math.Round((x.Count() / (double)orders.Count) * 100, 2) })
                .OrderByDescending(x => x.Num);
            var introduction = new { total = orders.Count, data = introductionData };
            var orderAreas = orders.GroupBy(x => x.AreaCode.Substring(0, 6))
                .Select(x => new { AreaCode = x.Key, Num = x.Count(), Rate = Math.Round((x.Count() / (double)orders.Count) * 100, 2) })
                .OrderByDescending(x => x.Num);
            var areaList = await _systemAreaRepository.Queryable().Where(x => x.Id.Length == 6).ToListAsync(cancellationToken);
            var areaData = (from t1 in orderAreas
                            join t2 in areaList on t1.AreaCode equals t2.Id into t1_t2
                            from item in t1_t2.DefaultIfEmpty()
                            select new
                            {
                                AreaCode = t1.AreaCode,
                                Num = t1.Num,
                                Rate = t1.Rate,
                                AreaName = t1_t2.Select(x => x.AreaName).FirstOrDefault(),
                            }).OrderByDescending(x => x.Num).ToList();
            var areaNames = areaData.Select(x => x.AreaName).ToList();

            var area = new { AreaNames = areaNames, data = areaData };

            var handle = new { HandleFiled = orders.Count(x => x.Status >= EOrderStatus.Filed), Handle = orders.Count(x => x.Status < Share.Enums.Order.EOrderStatus.Filed) };

            var first = _mapper.Map<List<OrderDto>>(orders.OrderByDescending(x => x.CreationTime).Take(2).ToList());
            return new { Analysis = analysis, Introduction = introduction, Area = area, Handle = handle, First = first };
        }


    }
}
