using DotNetCore.CAP;
using Hotline.Application.OrderApp;
using Hotline.Caching.Interfaces;
using Hotline.Configurations;
using Hotline.FlowEngine.Workflows;
using Hotline.Orders;
using Hotline.Push;
using Hotline.Push.Notifies;
using Hotline.SeedData;
using Hotline.Settings;
using Hotline.Settings.TimeLimitDomain;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Dtos.Push;
using Hotline.Share.Enums.FlowEngine;
using Hotline.Share.Enums.Order;
using Hotline.Share.Enums.Push;
using Hotline.Share.Mq;
using Hotline.Users;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using NPOI.SS.Formula.Functions;
using StackExchange.Redis;
using XF.Domain.Authentications;
using XF.Domain.Dependency;
using XF.Domain.Repository;

namespace Hotline.Application.Subscribers
{
    public class InternalCapSubscriber : ICapSubscribe, ITransientDependency
    {
        private readonly IOrderRepository _orderRepository;
        private readonly IMediator _mediator;
        private readonly IRepository<User> _userRepository;
        private readonly ICapPublisher _capPublisher;
        private readonly IRepository<BatchSmsTask> _batchSmsTaskRepository;
        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
        private readonly IOrderApplication _orderApplication;
        private readonly IRepository<OrderDelay> _orderDelayRepository;
        private readonly IWorkflowDomainService _workflowDomainService;
        private readonly ICalcExpireTime _expireTime;
        private readonly IMapper _mapper;
        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;

        public InternalCapSubscriber(
            IOrderRepository orderRepository,
            IMediator mediator,
            IRepository<User> userRepository,
            ICapPublisher capPublisher,
            IRepository<BatchSmsTask> batchSmsTaskRepository,
            ISystemSettingCacheManager systemSettingCacheManager,
            IOrderApplication orderApplication,
            IRepository<OrderDelay> orderDelayRepository,
            IWorkflowDomainService workflowDomainService,
            ICalcExpireTime expireTime,
            IMapper mapper
,
            IOptionsSnapshot<AppConfiguration> appOptions)
        {
            _orderRepository = orderRepository;
            _mediator = mediator;
            _userRepository = userRepository;
            _capPublisher = capPublisher;
            _batchSmsTaskRepository = batchSmsTaskRepository;
            _systemSettingCacheManager = systemSettingCacheManager;
            _orderApplication = orderApplication;
            _orderDelayRepository = orderDelayRepository;
            _workflowDomainService = workflowDomainService;
            _expireTime = expireTime;
            _mapper = mapper;
            _appOptions = appOptions;
        }

        /// <summary>
        /// 工单即将超期短信发送（延迟消息）
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        [CapSubscribe(EventNames.HotlineOrderNearlyExpiredTimeSms)]
        public async Task SendOrderNearlyExpiredTimeSms(PublishNearlyExpiredTimeSmsDto dto, CancellationToken cancellationToken)
        {
            var order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
            if (order != null && order.Status < Share.Enums.Order.EOrderStatus.Filed && order.NearlyExpiredTime?.ToString("yyyy-MM-dd hh:mm") == DateTime.Now.ToString("yyyy-MM-dd hh:mm"))
            {
                //当前办理人不为空发短信给个人
                if (!string.IsNullOrEmpty(order.CurrentHandlerId))
                {
                    //查询人员
                    var user = await _userRepository.GetAsync(order.CurrentHandlerId, cancellationToken);
                    if (user != null && !string.IsNullOrEmpty(user.PhoneNo))
                    {
                        //发送短信
                        var messageDto = new Share.Dtos.Push.MessageDto
                        {
                            PushBusiness = EPushBusiness.OrderUrge,
                            ExternalId = order.Id,
                            OrderId = order.Id,
                            PushPlatform = EPushPlatform.Sms,
                            Remark = order.Title,
                            Name = user.Name,
                            TemplateCode = "1001",
                            Params = new List<string>() { order.No },
                            TelNumber = user.PhoneNo,
                        };
                        await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
                    }
                }
                //当前办理部门不为空，发短信给部门经办人
                else if (!string.IsNullOrEmpty(order.CurrentHandleOrgId))
                {
                    var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
                    //查询部门经办人
                    var userlist = await _userRepository.Queryable().Where(x =>
                        x.OrgId == order.CurrentHandleOrgId && !string.IsNullOrEmpty(x.PhoneNo) &&
                        x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
                    foreach (var user in userlist)
                    {
                        if (!string.IsNullOrEmpty(user.PhoneNo))
                        {
                            //发送短信
                            var messageDto = new Share.Dtos.Push.MessageDto
                            {
                                PushBusiness = EPushBusiness.OrderUrge,
                                ExternalId = order.Id,
                                OrderId = order.Id,
                                PushPlatform = EPushPlatform.Sms,
                                Remark = order.Title,
                                Name = user.Name,
                                TemplateCode = "1001",
                                Params = new List<string>() { order.No },
                                TelNumber = user.PhoneNo,
                            };
                            await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
                        }
                    }
                }
                //TODO发送短信超期
                //_capPublisher.PublishDelay(order.ExpiredTime.Value- DateTime.Now, EventNames.HotlineOrderExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
            }
        }

        /// <summary>
        /// 工单超期短信发送（延迟消息）
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        [CapSubscribe(EventNames.HotlineOrderExpiredTimeSms)]
        public async Task SendOrderExpiredTimeSms(PublishNearlyExpiredTimeSmsDto dto, CancellationToken cancellationToken)
        {
            var order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
            if (order != null && order.Status < Share.Enums.Order.EOrderStatus.Filed && order.NearlyExpiredTime?.ToString("yyyy-MM-dd hh:mm") == DateTime.Now.ToString("yyyy-MM-dd hh:mm"))
            {
                //当前办理人不为空发短信给个人
                if (!string.IsNullOrEmpty(order.CurrentHandlerId))
                {
                    //查询人员
                    var user = await _userRepository.GetAsync(order.CurrentHandlerId, cancellationToken);
                    if (user != null && !string.IsNullOrEmpty(user.PhoneNo))
                    {
                        //发送短信
                        var messageDto = new Share.Dtos.Push.MessageDto
                        {
                            PushBusiness = EPushBusiness.OrderUrge,
                            ExternalId = order.Id,
                            OrderId = order.Id,
                            PushPlatform = EPushPlatform.Sms,
                            Remark = order.Title,
                            Name = user.Name,
                            TemplateCode = "1009",
                            Params = new List<string>() { order.No },
                            TelNumber = user.PhoneNo,
                        };
                        await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
                    }
                }
                //当前办理部门不为空，发短信给部门经办人
                else if (!string.IsNullOrEmpty(order.CurrentHandleOrgId))
                {
                    var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
                    //查询部门经办人
                    var userlist = await _userRepository.Queryable().Where(x =>
                        x.OrgId == order.CurrentHandleOrgId && !string.IsNullOrEmpty(x.PhoneNo) &&
                        x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
                    foreach (var user in userlist)
                    {
                        if (!string.IsNullOrEmpty(user.PhoneNo))
                        {
                            //发送短信
                            var messageDto = new Share.Dtos.Push.MessageDto
                            {
                                PushBusiness = EPushBusiness.OrderUrge,
                                ExternalId = order.Id,
                                OrderId = order.Id,
                                PushPlatform = EPushPlatform.Sms,
                                Remark = order.Title,
                                Name = user.Name,
                                TemplateCode = "1009",
                                Params = new List<string>() { order.No },
                                TelNumber = user.PhoneNo,
                            };
                            await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 批量发送短信（延迟消息）
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        [CapSubscribe(EventNames.HotlineBatchSmsTask)]
        public async Task SendBatchSmsTask(PublishBatchSmsTaskDto dto, CancellationToken cancellationToken)
        {
            var task = await _batchSmsTaskRepository.Queryable()
                .Includes(x => x.BatchSmsTaskDetails)
                .Where(x => x.Id == dto.TaskId).FirstAsync();
            if (task != null && task.SmsTaskState == ESmsTaskState.WaitDo && task.PlanSendTime.ToString("yyyy-MM-dd hh:mm") == DateTime.Now.ToString("yyyy-MM-dd hh:mm"))
            {
                foreach (var item in task.BatchSmsTaskDetails)
                {
                    //发送短信
                    var messageDto = new Share.Dtos.Push.MessageDto
                    {
                        PushBusiness = EPushBusiness.BatchSms,
                        PushPlatform = EPushPlatform.Sms,
                        Name = item.Name,
                        TelNumber = item.PhoneNum,
                        Content = task.Content
                    };
                    await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
                }
            }
        }

        /// <summary>
        /// 自动延期
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        [CapSubscribe(EventNames.HotlineOrderAutomaticDelay)]
        public async Task AutomaticDelay(PublishAutomaticDelayDto dto, CancellationToken cancellationToken)
        {
            var enabled = _systemSettingCacheManager.GetSetting(SettingConstants.EnabledAutomaticDelay)?.SettingValue[0];
            if (bool.Parse(enabled))
            {
                var order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
                var expiredTime = DateTime.Now.AddHours(2);
                if (order != null && order.Status < EOrderStatus.Filed && order.ExpiredTime >= DateTime.Now)
                {
                    if (order.ExpiredTime <= expiredTime)
                    {
                        var delayAny = await _orderDelayRepository.Queryable().Where(x => x.OrderId == order.Id && x.DelayState == EDelayState.Examining).AnyAsync();
                        if (!delayAny)
                        {
                            var delays = await _orderDelayRepository.Queryable().Where(x => x.OrderId == order.Id && x.AutomaticDelayNum > 0).ToListAsync(cancellationToken);
                            var delay = new OrderDelay();
                            if (delays.Any())
                            {
                                delay = delays.First();
                                var startTime = DateTime.Now;
                                if (order.CenterToOrgTime.HasValue)
                                {
                                    startTime = order.CenterToOrgTime.Value;
                                }
                                var beforeDelay = DateTime.Now;
                                if (!_appOptions.Value.IsYiBin)
                                {
                                    beforeDelay = order.ExpiredTime.Value;
                                }
                                delay.AfterDelay = (await _expireTime
                                    .CalcEndTime(beforeDelay, startTime, delay.DelayUnit, delay.DelayNum, order.AcceptTypeCode))?.EndTime; //todo
                                await _orderDelayRepository.Updateable().SetColumns(x => new OrderDelay() { AutomaticDelayNum = x.AutomaticDelayNum + 1, ApplyDelayTime = DateTime.Now, AfterDelay = delay.AfterDelay })
                                    .Where(x => x.Id == delay.Id).ExecuteCommandAsync(cancellationToken);
                            }
                            else
                            {
                                delay.OrderId = order.Id;
                                delay.EmployeeId = "";
                                delay.EmployeeName = "系统自动延期";
                                delay.ApplyOrgName = OrgSeedData.CenterName;
                                delay.ApplyOrgCode = OrgSeedData.CenterId;
                                delay.DelayApplyType = EDelayApplyType.LocalApply;
                                delay.BeforeDelay = order.ExpiredTime;
                                delay.DelayState = EDelayState.Pass;
                                delay.DelayReason = "系统自动延期";
                                delay.ApplyDelayTime = DateTime.Now;
                                delay.No = order.No;
                                delay.AutomaticDelayNum = 1;
                                delay.DelayNum = 1;
                                delay.DelayUnit = Share.Enums.Settings.ETimeType.WorkDay;
                                delay.IsProDelay = false;
                                delay.CreatorOrgId = OrgSeedData.CenterId;
                                delay.CreatorOrgName = OrgSeedData.CenterName;
                                delay.CreatorName = "系统自动延期";
                                var startTime = DateTime.Now;
                                if (order.CenterToOrgTime.HasValue)
                                {
                                    startTime = order.CenterToOrgTime.Value;
                                }
                                if (delay.BeforeDelay != null)
                                {
                                    delay.AfterDelay = (await _expireTime
                                        .CalcEndTime(delay.BeforeDelay.Value, startTime, delay.DelayUnit, delay.DelayNum, order.AcceptTypeCode))?.EndTime; //todo
                                }
                                await _orderDelayRepository.AddAsync(delay, false, cancellationToken);
                            }
                            //处理工单延期
                            await _orderApplication.DelayOrderExpiredTimeAsync(order.Id, delay.DelayNum, delay.DelayUnit, delay.IsProDelay, cancellationToken);

                            // 自贡任务 320调整“延期催办短信”发送的时间，将短信发送时间提前2个小时，所以拆分出去
                            ////发送短信
                            //var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, cancellationToken: cancellationToken);
                            //var steps = workflow.Steps.Where(x => x.Status == EWorkflowStepStatus.WaitForAccept || x.Status == EWorkflowStepStatus.WaitForHandle).ToList();
                            //if (steps.Any())
                            //{
                            //	foreach (var step in steps)
                            //	{
                            //		var setting = step.HandlerOrgId == OrgSeedData.CenterId ? SettingConstants.AutomaticDelayCenterRoles : SettingConstants.AutomaticDelayDepartmentRoles;
                            //		var roleIds = _systemSettingCacheManager.GetSetting(setting)?.SettingValue;
                            //		if (step.HandlerOrgId == OrgSeedData.CenterId && string.IsNullOrEmpty(step.RoleId))
                            //		{
                            //			roleIds.Add(step.RoleId);
                            //		}
                            //		var userList = await _userRepository.Queryable().Where(x => x.OrgId == step.HandlerOrgId && x.Roles.Any(r => roleIds.Contains(r.Name))).ToListAsync(cancellationToken);
                            //		foreach (var user in userList)
                            //		{
                            //			if (!string.IsNullOrEmpty(user.PhoneNo))
                            //			{
                            //				//发送短信
                            //				var messageDto = new Share.Dtos.Push.MessageDto
                            //				{
                            //					PushBusiness = EPushBusiness.AutomaticDelay,
                            //					ExternalId = order.Id,
                            //					OrderId = order.Id,
                            //					PushPlatform = EPushPlatform.Sms,
                            //					Remark = order.Title,
                            //					Name = user.Name,
                            //					TemplateCode = "1015",
                            //					Params = new List<string>() { order.No },
                            //					TelNumber = user.PhoneNo,
                            //				};
                            //				await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
                            //			}
                            //		}
                            //	}
                            //}
                        }
                    }
                    order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
                    _capPublisher.PublishDelay(order.ExpiredTime.Value - DateTime.Now.AddHours(1), EventNames.HotlineOrderAutomaticDelay, new PublishAutomaticDelayDto() { OrderId = order.Id });
                    var orderDto = _mapper.Map<OrderDto>(order);
                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
                        cancellationToken: cancellationToken);
                }
            }

        }

        /// <summary>
        /// 延期催办短信（延迟消息，自动延期前2小时发送）
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        [CapSubscribe(EventNames.HotlineOrderAutomaticSendSmsDelay)]
        public async Task AutomaticDelaySendSms(PublishAutomaticDelayDto dto, CancellationToken cancellationToken)
        {
            var enabled = _systemSettingCacheManager.GetSetting(SettingConstants.EnabledAutomaticDelay)?.SettingValue[0];
            if (bool.Parse(enabled))
            {
                var order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
                var expiredTime = DateTime.Now.AddHours(2);
                if (order != null && order.Status < EOrderStatus.Filed && order.ExpiredTime >= DateTime.Now)
                {
                    if (order.ExpiredTime <= expiredTime)
                    {
                        var delayAny = await _orderDelayRepository.Queryable().Where(x => x.OrderId == order.Id && x.DelayState == EDelayState.Examining).AnyAsync();
                        if (!delayAny)
                        {
                            //发送短信
                            var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, cancellationToken: cancellationToken);
                            var steps = workflow.Steps.Where(x => x.Status == EWorkflowStepStatus.WaitForAccept || x.Status == EWorkflowStepStatus.WaitForHandle).ToList();
                            if (steps.Any())
                            {
                                foreach (var step in steps)
                                {
                                    var setting = step.HandlerOrgId == OrgSeedData.CenterId ? SettingConstants.AutomaticDelayCenterRoles : SettingConstants.AutomaticDelayDepartmentRoles;
                                    var roleIds = _systemSettingCacheManager.GetSetting(setting)?.SettingValue;
                                    if (step.HandlerOrgId == OrgSeedData.CenterId && string.IsNullOrEmpty(step.RoleId))
                                    {
                                        roleIds.Add(step.RoleId);
                                    }
                                    var userList = await _userRepository.Queryable().Where(x => x.OrgId == step.HandlerOrgId && x.Roles.Any(r => roleIds.Contains(r.Name))).ToListAsync(cancellationToken);
                                    foreach (var user in userList)
                                    {
                                        if (!string.IsNullOrEmpty(user.PhoneNo))
                                        {
                                            //发送短信
                                            var messageDto = new Share.Dtos.Push.MessageDto
                                            {
                                                PushBusiness = EPushBusiness.AutomaticDelay,
                                                ExternalId = order.Id,
                                                OrderId = order.Id,
                                                PushPlatform = EPushPlatform.Sms,
                                                Remark = order.Title,
                                                Name = user.Name,
                                                TemplateCode = "1015",
                                                Params = new List<string>() { order.No },
                                                TelNumber = user.PhoneNo,
                                            };
                                            await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 批量发送短信
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        [CapSubscribe(EventNames.HotlineLeaderSMS)]
        public async Task SendLeaderSMS(PublishLeaderSMSDto dto, CancellationToken cancellationToken)
        {
            //发送短信
            var messageDto = new Share.Dtos.Push.MessageDto
            {
                PushBusiness = EPushBusiness.OrderSend,
                ExternalId = dto.OrderId,
                OrderId = dto.OrderId,
                PushPlatform = EPushPlatform.Sms,
                Remark = string.Empty,
                Name = dto.Name,
                TemplateCode = "1014",
                Params = new(),
                TelNumber = dto.TelNumber,
            };
            await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
        }
    }
}
