using DotNetCore.CAP;
using Hotline.Configurations;
using Hotline.FlowEngine.Notifications;
using Hotline.FlowEngine.WorkflowModules;
using Hotline.FlowEngine.Workflows;
using Hotline.Orders;
using Hotline.Push.Notifies;
using Hotline.Repository.SqlSugar.Orders;
using Hotline.Settings.TimeLimitDomain;
using Hotline.Settings.TimeLimits;
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.Enums.Settings;
using Hotline.Users;
using MapsterMapper;
using MediatR;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using XF.Domain.Authentications;
using XF.Domain.Repository;

namespace Hotline.Application.Handlers.FlowEngine
{
    public class WorkflowPreviousHandler : INotificationHandler<PreviousNotify>
    {
        private readonly IOrderDomainService _orderDomainService;
        private readonly IOrderRepository _orderRepository;
        private readonly IOrderScreenRepository _orderScreenRepository;
        private readonly IOrderDelayRepository _orderDelayRepository;
        private readonly IWorkflowDomainService _workflowDomainService;
        private readonly ITimeLimitDomainService _timeLimitDomainService;
        private readonly ICapPublisher _capPublisher;
        private readonly IMapper _mapper;
        private readonly ILogger<WorkflowPreviousHandler> _logger;
        private readonly IRepository<User> _userRepository;
        private readonly IMediator _mediator;
        private readonly ISessionContext _sessionContext;
        private readonly IRepository<OrderScreenDetail> _orderScreenDetailRepository;
        private readonly IRepository<OrderTerminate> _orderTerminateRepository;
        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
        private readonly ICalcExpireTime _expireTime;
        private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;

        public WorkflowPreviousHandler(
            IOrderDomainService orderDomainService,
            IOrderRepository orderRepository,
            IOrderScreenRepository orderScreenRepository,
            IOrderDelayRepository orderDelayRepository,
            IWorkflowDomainService workflowDomainService,
            ITimeLimitDomainService timeLimitDomainService,
            ICapPublisher capPublisher,
            IMapper mapper,
            ILogger<WorkflowPreviousHandler> logger,
            IRepository<User> userRepository,
            IMediator mediator,
            ISessionContext sessionContext,
            IRepository<OrderScreenDetail> orderScreenDetailRepository,
            IRepository<OrderTerminate> orderTerminateRepository,
            IOptionsSnapshot<AppConfiguration> appOptions,
            ICalcExpireTime expireTime,
             IRepository<OrderVisitDetail> orderVisitDetailRepository
            )
        {
            _orderDomainService = orderDomainService;
            _orderRepository = orderRepository;
            _workflowDomainService = workflowDomainService;
            _timeLimitDomainService = timeLimitDomainService;
            _capPublisher = capPublisher;
            _mapper = mapper;
            _logger = logger;
            _userRepository = userRepository;
            _mediator = mediator;
            _orderScreenRepository = orderScreenRepository;
            _orderDelayRepository = orderDelayRepository;
            _sessionContext = sessionContext;
            _orderScreenDetailRepository = orderScreenDetailRepository;
            _orderTerminateRepository = orderTerminateRepository;
            _appOptions = appOptions;
            _expireTime = expireTime;
            _orderVisitDetailRepository = orderVisitDetailRepository;
        }

        /// <summary>Handles a notification</summary>
        /// <param name="notification">The notification</param>
        /// <param name="cancellationToken">Cancellation token</param>
        public async Task Handle(PreviousNotify notification, CancellationToken cancellationToken)
        {
            try
            {
                var workflow = notification.Workflow;
                var data = notification.Dto;

                switch (workflow.ModuleCode)
                {
                    case WorkflowModuleConsts.OrderHandle:
                    case WorkflowModuleConsts.OrderHandleSnapshot:
                        var order = await _orderDomainService.GetOrderAsync(workflow.ExternalId, withHotspot: true, withAcceptor: true,
                            withExtension: true, cancellationToken: cancellationToken);
                        order.CheckIfFiled();
                        //order.UpdateHandlingStatus(workflow.IsInCountersign);
                        _mapper.Map(workflow, order);
                        if (notification.TargetStep.StepType is EStepType.Start)
                        {
                            order.Status = EOrderStatus.BackToUnAccept;
                            //order.BackToUnsign();
                        }
                        else
                        {
                            order.Status = EOrderStatus.SendBack;
                        }

                        await _orderRepository.UpdateAsync(order, cancellationToken);
                        //if (notification.IsOrgToCenter)
                        //{
                        //    var expiredTimeConfig = _timeLimitDomainService.CalcExpiredTime(DateTime.Now, EFlowDirection.OrgToCenter, order.AcceptTypeCode);

                        //    await _workflowDomainService.UpdateExpiredTimeAsync(workflow, expiredTimeConfig.ExpiredTime,
                        //        expiredTimeConfig.TimeText, expiredTimeConfig.Count, expiredTimeConfig.TimeType, expiredTimeConfig.NearlyExpiredTime, cancellationToken);

                        //    var dto = _mapper.Map<OrderDto>(order);
                        //    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, dto, cancellationToken: cancellationToken);
                        //    //try
                        //    //{
                        //    //    await _provinceService.HotlineOrderFlowRecalled(dto, cancellationToken);
                        //    //}
                        //    //catch (Exception e)
                        //    //{
                        //    //    _logger.LogError("_provinceService.HotlineOrderFlowRecalled throw exception: {ex}",
                        //    //        e.Message);
                        //    //}
                        //}
                        if (notification.Dto.AcceptSms)
                        {
                            var targetStep = notification.TargetStep;

                            switch (targetStep.HandlerType)
                            {
                                case EHandlerType.Role:
                                case EHandlerType.AssignedUser:
                                    var users = await _userRepository.Queryable()
                                        .Where(d => targetStep.Handlers.Select(x => x.Key).Contains(d.Id))
                                        .ToListAsync(cancellationToken);
                                    foreach (var user in users)
                                    {
                                        if (!string.IsNullOrEmpty(user.PhoneNo))
                                        {
                                            var messageDto = new MessageDto()
                                            {
                                                PushBusiness = EPushBusiness.OrderSendBack,
                                                ExternalId = order.Id,
                                                OrderId = order.Id,
                                                PushPlatform = EPushPlatform.Sms,
                                                Remark = order.Title,
                                                Name = user.Name,
                                                TemplateCode = "1004",
                                                Params = new List<string>() { order.No },
                                                TelNumber = user.PhoneNo,
                                            };
                                            await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
                                        }
                                    }
                                    break;
                                case EHandlerType.OrgLevel:
                                case EHandlerType.OrgType:
                                case EHandlerType.AssignedOrg:
                                    //todo 部门经办人联系方式
                                    break;
                                default:
                                    throw new ArgumentOutOfRangeException();
                            }
                        }


                        break;
                    case WorkflowModuleConsts.OrderDelay:
                        var delay = await _orderDelayRepository.GetAsync(workflow.ExternalId, cancellationToken);
                        if (delay != null)
                        {
                            delay.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
                            await _orderDelayRepository.UpdateAsync(delay, cancellationToken);
                        }
                        break;
                    case WorkflowModuleConsts.OrderScreen:
                        var workflowSteps = await _workflowDomainService.GetWorkflowAsync(workflow.Id, withSteps: true, cancellationToken: cancellationToken);
                        var screen = await _orderScreenRepository.GetAsync(workflow.ExternalId, cancellationToken);
                        if (screen != null)
                        {
                            screen.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
                            screen.SendBackTime = DateTime.Now;
                            screen.SendBackApply = workflowSteps.Steps.Any(x => x is { Status: EWorkflowStepStatus.WaitForHandle or EWorkflowStepStatus.WaitForAccept, StepType: EStepType.Start, IsOrigin: true });
                            screen.Status = EScreenStatus.SendBack;
                            screen.SendBackNum++;
                            await _orderScreenRepository.UpdateAsync(screen, cancellationToken);
                            //自贡任务 220 修改甄别截止申请日期的计算方式
                            //甄别截止申请日期=回访时间+2个工作日  ，若退回到申请人节点，甄别截止申请日期=退回时间+2个工作日
                            if (screen.SendBackApply == true && _appOptions.Value.IsZiGong)
                            {
                                var orderVisitDetail = await _orderVisitDetailRepository.GetAsync(p => p.Id == screen.VisitDetailId, cancellationToken);
                                if (orderVisitDetail != null)
                                {
                                    orderVisitDetail.ScreenByEndTime = (await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, ETimeType.WorkDay, 2, 0, 0)).EndTime;
                                    await _orderVisitDetailRepository.UpdateAsync(orderVisitDetail, cancellationToken);
                                }
                            }
                        }
                        OrderScreenDetail detail = new OrderScreenDetail
                        {
                            ScreenId = screen.Id
                        };
                        detail.Audit(_sessionContext.UserId, _sessionContext.UserName, _sessionContext.OrgId, _sessionContext.OrgName, 2);
                        await _orderScreenDetailRepository.AddAsync(detail, cancellationToken);
                        break;
                    case WorkflowModuleConsts.KnowledgeAdd:
                    case WorkflowModuleConsts.KnowledgeUpdate:
                    case WorkflowModuleConsts.KnowledgeDelete:
                    case WorkflowModuleConsts.KnowledgeOffshelf:
                    case WorkflowModuleConsts.TelRestApply:
                        break;
                    case WorkflowModuleConsts.OrderTerminate:
                        var orderTerminate = await _orderTerminateRepository.Queryable()
                            .Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
                        if (orderTerminate != null)
                        {
                            orderTerminate.Status = ETerminateStatus.SendBack;
                            if (notification.TargetStep.StepType is EStepType.Start)
                            {
                                orderTerminate.Status = ETerminateStatus.SendBackStart;
                            }
                            await _orderTerminateRepository.UpdateAsync(orderTerminate, cancellationToken);
                        }
                        break;
                }

            }
            catch (Exception e)
            {
                _logger.LogError($"{nameof(WorkflowPreviousHandler)}异常，{e}");
                throw;
            }
        }
    }
}