using DotNetCore.CAP;
using Hotline.Application.JudicialManagement;
using Hotline.Application.Quality;
using Hotline.Caching.Interfaces;
using Hotline.EventBus;
using Hotline.FlowEngine.Notifications;
using Hotline.FlowEngine.WorkflowModules;
using Hotline.FlowEngine.Workflows;
using Hotline.JudicialManagement.Notifies;
using Hotline.KnowledgeBase;
using Hotline.Orders;
using Hotline.Push.Notifies;
using Hotline.Settings;
using Hotline.Settings.TimeLimits;
using Hotline.Share.Dtos.FlowEngine.Workflow;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Enums.FlowEngine;
using Hotline.Share.Enums.Order;
using Hotline.Share.Enums.Push;
using Hotline.Share.Enums.Quality;
using Hotline.Share.Mq;
using Hotline.Users;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using XF.Domain.Authentications;
using XF.Domain.Entities;
using XF.Domain.Repository;

namespace Hotline.Application.Handlers.FlowEngine;

public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
{
    private readonly IOrderDomainService _orderDomainService;
    private readonly IOrderRepository _orderRepository;
    private readonly ICapPublisher _capPublisher;
    private readonly IMapper _mapper;
    private readonly ILogger<WorkflowNextHandler> _logger;
    private readonly IQualityApplication _qualityApplication;
    private readonly IOrderDelayRepository _orderDelayRepository;
    private readonly IKnowledgeRepository _knowledgeRepository;
    private readonly ISessionContext _sessionContext;
    private readonly IRepository<User> _userRepository;
    private readonly IMediator _mediator;
    private readonly ISystemSettingCacheManager _systemSettingCacheManager;
    private readonly Publisher _publisher;

    public WorkflowNextHandler(
        IOrderDomainService orderDomainService,
        IOrderRepository orderRepository,
        ICapPublisher capPublisher,
        IMapper mapper,
        ILogger<WorkflowNextHandler> logger,
        IQualityApplication qualityApplication,
        IKnowledgeRepository knowledgeRepository,
        ISessionContext sessionContext,
        IOrderDelayRepository orderDelayRepository,
        IRepository<User> userRepository,
        IMediator mediator,
        ISystemSettingCacheManager systemSettingCacheManager,
        Publisher publisher)
    {
        _orderDomainService = orderDomainService;
        _orderRepository = orderRepository;
        _capPublisher = capPublisher;
        _mapper = mapper;
        _logger = logger;
        _qualityApplication = qualityApplication;
        _orderDelayRepository = orderDelayRepository;
        _knowledgeRepository = knowledgeRepository;
        _sessionContext = sessionContext;
        _userRepository = userRepository;
        _mediator = mediator;
        _systemSettingCacheManager = systemSettingCacheManager;
        _publisher = publisher;
    }

    /// <summary>Handles a notification</summary>
    /// <param name="notification">The notification</param>
    /// <param name="cancellationToken">Cancellation token</param>
    public async Task Handle(NextStepNotify notification, CancellationToken cancellationToken)
    {
        try
        {
            //_logger.LogInformation(
            //    $"收到{nameof(NextStepNotify)}, notification: {JsonConvert.SerializeObject(notification)}");
            var workflow = notification.Workflow;
            var data = notification.Dto;
            var assignInfo = notification.FlowAssignInfo;

            var currentTag = string.IsNullOrEmpty(notification.Trace.Tag)
                ? null
                : System.Text.Json.JsonSerializer.Deserialize<DefinitionTag>(notification.Trace.Tag);
            var nextTag = string.IsNullOrEmpty(notification.NextStepDefine.Tag)
                ? null
                : System.Text.Json.JsonSerializer.Deserialize<DefinitionTag>(notification.NextStepDefine.Tag);

            switch (workflow.ModuleCode)
            {
                case WorkflowModuleConsts.OrderHandle:
                    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);

                    //var expiredTimeChanged = false;
                    //if (data.FlowDirection.HasValue
                    //    && data.External.TimeLimit.HasValue                   
                    //    && data.External.TimeLimitUnit.HasValue)
                    //{
                    //    // 1. calc expiredTime 2. update order.expiredTime 3. update workflow.expiredTime 4. publish province

                    //    // var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now,
                    //    //     data.External.TimeLimitUnit.Value,
                    //    //     data.External.TimeLimit.Value, data.FlowDirection is EFlowDirection.OrgToCenter);

                    //    var expiredTimeConfig = _timeLimitDomainService.CalcEndTime(DateTime.Now,
                    //        new TimeConfig(data.External.TimeLimit.Value, data.External.TimeLimitUnit.Value), order.AcceptTypeCode);

                    //    if (data.FlowDirection is EFlowDirection.OrgToCenter)
                    //    {
                    //        order.OrgToCenter(expiredTimeConfig.TimeText, expiredTimeConfig.Count,
                    //            expiredTimeConfig.TimeType, expiredTimeConfig.ExpiredTime, expiredTimeConfig.NearlyExpiredTime);
                    //    }
                    //    else if (data.FlowDirection is EFlowDirection.CenterToOrg)
                    //    {
                    //        order.CenterToOrg(expiredTimeConfig.TimeText, expiredTimeConfig.Count,
                    //            expiredTimeConfig.TimeType, expiredTimeConfig.ExpiredTime, expiredTimeConfig.NearlyExpiredTime);
                    //        //写入质检
                    //        await _qualityApplication.AddQualityAsync(EQualitySource.Send, order.Id, cancellationToken);
                    //    }

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

                    //    expiredTimeChanged = true;
                    //}
                    await _orderRepository.Updateable(order).ExecuteCommandAsync(cancellationToken);
                    //await _orderRepository.UpdateAsync(order, cancellationToken);

                    //司法行政监督管理-推诿工单
                    //如果没开启则不处理
                    var isOpenJudicialManagement = _systemSettingCacheManager.GetSetting(SettingConstants.IsOpenJudicialManagement)?.SettingValue[0];
                    if (isOpenJudicialManagement == "true" && notification.Trace.StepType != EStepType.Summary && notification.Trace.StepType != EStepType.End && !notification.Trace.IsCountersignEndStep)
                        await _publisher.PublishAsync(new AddPassTheBuckOrderNotify(order, _sessionContext.RequiredOrgId, _sessionContext.OrgName),
                            PublishStrategy.ParallelWhenAll, cancellationToken);

                    try
                    {
                        if (notification.Dto.IsSms)
                        {
                            switch (notification.FlowAssignInfo.FlowAssignType)
                            {
                                case EFlowAssignType.Org:
                                    var orgCodes = notification.FlowAssignInfo.HandlerObjects.Select(x => x.Key);
                                    var orgList = await _userRepository.Queryable()
                                        .Where(x => orgCodes.Contains(x.OrgId) && x.Roles.Any(d => d.Id == "08dae71e-0eca-4bc4-89fe-7eaefae8a98e"))
                                        .ToListAsync(cancellationToken);
                                    foreach (var item in orgList)
                                    {
                                        if (!string.IsNullOrEmpty(item.PhoneNo))
                                        {
                                            var messageDto = new Share.Dtos.Push.MessageDto
                                            {
                                                PushBusiness = EPushBusiness.OrderSend,
                                                ExternalId = order.Id,
                                                OrderId = order.Id,
                                                PushPlatform = EPushPlatform.Sms,
                                                Remark = order.Title,
                                                Name = item.Name,
                                                TemplateCode = "1007",
                                                Params = new List<string>() { order.No },
                                                TelNumber = item.PhoneNo,

                                            };
                                            await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
                                        }
                                    }
                                    break;
                                case EFlowAssignType.User:
                                    var userCodes = notification.FlowAssignInfo.HandlerObjects.Select(x => x.Key);
                                    var userList = await _userRepository.Queryable()
                                        .Where(x => userCodes.Contains(x.Id) && x.Roles.Any(d => d.Id == "08dae71e-0eca-4bc4-89fe-7eaefae8a98e"))
                                        .ToListAsync(cancellationToken);
                                    foreach (var item in userList)
                                    {
                                        var messageDto = new Share.Dtos.Push.MessageDto
                                        {
                                            PushBusiness = EPushBusiness.OrderSend,
                                            ExternalId = order.Id,
                                            OrderId = order.Id,
                                            PushPlatform = EPushPlatform.Sms,
                                            Remark = order.Title,
                                            Name = item.Name,
                                            TemplateCode = "1007",
                                            Params = new List<string>() { order.No },
                                            TelNumber = item.PhoneNo,

                                        };
                                        await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
                                    }
                                    break;
                                default:
                                    break;
                            }
                        }
                    }
                    catch { }
                    var orderDto = _mapper.Map<OrderDto>(order);
                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowHandled, new OrderFlowDto
                    {
                        Order = orderDto,
                        WorkflowTrace = _mapper.Map<WorkflowTraceDto>(notification.Trace),
                        ExpiredTimeChanged = notification.ExpiredTimeChanged,
                        HandlerOrgLevel = notification.HandlerOrgId.CalcOrgLevel()
                    }, cancellationToken: cancellationToken);
                    if (data.FlowDirection is EFlowDirection.CenterToOrg)
	                    await _qualityApplication.AddQualityAsync(EQualitySource.Send, order.Id, cancellationToken);

					break;
                case WorkflowModuleConsts.KnowledgeAdd:
                case WorkflowModuleConsts.KnowledgeUpdate:
                case WorkflowModuleConsts.KnowledgeDelete:
                    //var knowledgeWork = await _knowledgeWorkFlowRepository.Queryable().Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
                    var knowledge = await _knowledgeRepository.Queryable().Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
                    knowledge.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
                    await _knowledgeRepository.UpdateAsync(knowledge, cancellationToken);
                    break;
                //case WorkflowModuleConsts.OrderScreen:
                //    var screen = await _orderScreenRepository.Queryable().Includes(x => x.Order)
                //        .Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
                //    if (screen != null)
                //    {
                //        screen.Status = EScreenStatus.Approval;
                //        screen.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
                //        //如果下个节点是省审批，则修改为省甄别
                //        if (nextTag is not null && nextTag.Type == TagDefaults.TagType.Org && nextTag.Value == TagDefaults.TagValue.Province)
                //            screen.IsProScreen = true;
                //        await _orderScreenRepository.UpdateAsync(screen, cancellationToken);
                //    }

                //    if (nextTag is not null && nextTag.Type == TagDefaults.TagType.Org)
                //    {
                //        switch (nextTag.Value)
                //        {
                //            case TagDefaults.TagValue.Province:
                //                if (screen != null)
                //                {
                //                    var screenDto = _mapper.Map<OrderScreenListDto>(screen);
                //                    if (screen.Order != null && screen.Order.Source == ESource.ProvinceStraight)
                //                    {
                //                        var screenOrderDto = _mapper.Map<OrderDto>(screen.Order);
                //                        //推省上
                //                        _capPublisher.Publish(EventNames.HotlineOrderScreenApply, new PublishScreenDto()
                //                        {
                //                            Order = screenOrderDto,
                //                            Screen = screenDto,
                //                            ClientGuid = ""
                //                        });
                //                        //try
                //                        //{
                //                        //    await _provinceService.ScreenCaseInfoSend(new PublishScreenDto()
                //                        //    {
                //                        //        Order = screenOrderDto,
                //                        //        Screen = screenDto,
                //                        //        ClientGuid = ""
                //                        //    }, cancellationToken);
                //                        //}
                //                        //catch (Exception e)
                //                        //{
                //                        //    _logger.LogError(
                //                        //        "_provinceService.ScreenCaseInfoSend throw exception: {ex}", e.Message);
                //                        //}
                //                    }
                //                }

                //                break;
                //        }
                //    }

                //OrderScreenDetail detail = new OrderScreenDetail
                //{
                //	ScreenId = screen.Id
                //};
                //detail.Audit(_sessionContext.UserId, _sessionContext.UserName, _sessionContext.OrgId, _sessionContext.OrgName, 1);
                //await _orderScreenDetailRepository.AddAsync(detail, cancellationToken);
                //break;
                case WorkflowModuleConsts.OrderDelay:
                    var orderDelay = await _orderDelayRepository.Queryable().Includes(x => x.Order)
                        .Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
                    if (orderDelay != null)
                    {
                        orderDelay.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
                        await _orderDelayRepository.UpdateAsync(orderDelay, cancellationToken);
                    }


                    if (nextTag is not null && nextTag.Type == TagDefaults.TagType.Org)
                    {
                        switch (nextTag.Value)
                        {
                            case TagDefaults.TagValue.Province:
                                //TODO 发起省延期审批
                                //var orderDelay = await _orderDelayRepository.Queryable().Includes(x => x.Order)
                                //    .Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
                                try
                                {
                                    if (orderDelay != null)
                                    {
                                        orderDelay.DelayApplyType = EDelayApplyType.ProvinceApply;
                                        orderDelay.IsProDelay = true;
                                        await _orderDelayRepository.UpdateAsync(orderDelay);
                                        //推送
                                        var publishOrderDelay = _mapper.Map<PublishOrderDelayDto>(orderDelay);
                                        await _capPublisher.PublishAsync(EventNames.HotlineOrderApplyDelay, publishOrderDelay, cancellationToken: cancellationToken);

                                        //await _provinceService.DelayCaseInfoSend(publishOrderDelay, cancellationToken);
                                    }
                                }
                                catch (Exception e)
                                {
                                    _logger.LogError("_provinceService.DelayCaseInfoSend throw exception: {ex}",
                                        e.Message);
                                }

                                break;
                        }
                    }

                    break;
            }

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