using DotNetCore.CAP;
using Hotline.Application.JudicialManagement;
using Hotline.Application.Orders;
using Hotline.Application.Quality;
using Hotline.Article;
using Hotline.CallCenter.Calls;
using Hotline.CallCenter.Tels;
using Hotline.FlowEngine.Notifications;
using Hotline.FlowEngine.WorkflowModules;
using Hotline.KnowledgeBase;
using Hotline.Orders;
using Hotline.Settings.TimeLimits;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.FlowEngine.Workflow;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Dtos.TrCallCenter;
using Hotline.Share.Enums.Order;
using Hotline.Share.Enums.Quality;
using MapsterMapper;
using MediatR;
using Microsoft.Extensions.Logging;
using XF.Domain.Authentications;
using XF.Domain.Repository;

namespace Hotline.Application.Handlers.FlowEngine;

public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
{

    private readonly IKnowledgeDomainService _knowledgeDomainService;
    private readonly IOrderDomainService _orderDomainService;
    private readonly IOrderApplication _orderApplication;
    private readonly ITelDomainService _telDomainService;
    private readonly IOrderRepository _orderRepository;
    private readonly ICapPublisher _capPublisher;
    private readonly IMapper _mapper;
    private readonly IRepository<OrderVisitDetail> _orderVisitedDetailRepository;
    private readonly IRepository<OrderScreen> _orderScreenRepository;
    private readonly IRepository<Circular> _circularRepository;
    private readonly IRepositorySqlSugar<CircularReadGroup> _circularReadGroupRepository;
    private readonly IRepositorySqlSugar<CircularRecord> _circularRecordRepository;
    private readonly ICircularRecordDomainService _circularRecordDomainService;
    private readonly IRepository<OrderVisit> _orderVisitRepository;
    private readonly IRepository<OrderDelay> _orderDelayRepository;
    private readonly IRepository<OrderVisitApply> _orderVisitApplyRepository;
    private readonly ITimeLimitDomainService _timeLimitDomainService;
    private readonly IMediator _mediator;
    private readonly ILogger<WorkflowEndHandler> _logger;
    private readonly IKnowledgeRepository _knowledgeRepository;
    private readonly IKnowledgeWorkFlowRepository _knowledgeWorkFlowRepository;
    private readonly IRepository<TrCallRecord> _trCallRecordRepository;
    private readonly IQualityApplication _qualityApplication;
    private readonly IEnforcementApplication _enforcementApplication;
    private readonly ISessionContext _sessionContext;

    public WorkflowEndHandler(
        IKnowledgeDomainService knowledgeDomainService,
        IOrderDomainService orderDomainService,
        IOrderApplication orderApplication,
        ITelDomainService telDomainService,
        IOrderRepository orderRepository,
        ICapPublisher capPublisher,
        IMapper mapper,
        IRepository<OrderVisitDetail> orderVisitedDetailRepository,
        IRepository<OrderScreen> orderScreenRepository,
        IRepository<Bulletin> bulletinRepository,
        IRepository<Circular> circularRepository,
        IRepository<CircularReadGroup> circularReadGroupRepository,
        IRepository<CircularRecord> circularRecordRepository,
        ICircularRecordDomainService circularRecordDomainService,
        IRepository<OrderDelay> orderDelayRepository,
        IRepository<OrderVisit> orderVisitRepository,
        IRepository<OrderVisitApply> orderVisitApplyRepository,
        ITimeLimitDomainService timeLimitDomainService,
        IMediator mediator,
        IKnowledgeRepository knowledgeRepository,
        IKnowledgeWorkFlowRepository knowledgeWorkFlowRepository,
        ILogger<WorkflowEndHandler> logger,
        IRepository<TrCallRecord> trCallRecordRepository,
         IQualityApplication qualityApplication,
        IEnforcementApplication enforcementApplication,
        ISessionContext sessionContext)
    {
        _knowledgeDomainService = knowledgeDomainService;
        _orderDomainService = orderDomainService;
        _orderApplication = orderApplication;
        _telDomainService = telDomainService;
        _orderRepository = orderRepository;
        _capPublisher = capPublisher;
        _mapper = mapper;
        _orderScreenRepository = orderScreenRepository;
        _orderVisitedDetailRepository = orderVisitedDetailRepository;
        _circularRepository = circularRepository;
        _circularReadGroupRepository = circularReadGroupRepository;
        _circularRecordRepository = circularRecordRepository;
        _circularRecordDomainService = circularRecordDomainService;
        _orderDelayRepository = orderDelayRepository;
        _orderVisitRepository = orderVisitRepository;
        _orderVisitApplyRepository = orderVisitApplyRepository;
        _timeLimitDomainService = timeLimitDomainService;
        _mediator = mediator;
        _logger = logger;
        _knowledgeRepository = knowledgeRepository;
        _knowledgeWorkFlowRepository = knowledgeWorkFlowRepository;
        _trCallRecordRepository = trCallRecordRepository;
        _qualityApplication = qualityApplication;
        _enforcementApplication = enforcementApplication;
        _sessionContext = sessionContext;
    }

    /// <summary>Handles a notification</summary>
    /// <param name="notification">The notification</param>
    /// <param name="cancellationToken">Cancellation token</param>
    public async Task Handle(EndWorkflowNotify notification, CancellationToken cancellationToken)
    {
        var workflow = notification.Workflow;
        //审批是否通过
        var isReviewPass = workflow.IsReviewPass();

        switch (workflow.ModuleCode)
        {
            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 == knowledgeWork.KnowledgeId).FirstAsync(cancellationToken);
                knowledge.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
                await _knowledgeRepository.UpdateAsync(knowledge, cancellationToken);
                if (isReviewPass)
                {
                    await _knowledgeDomainService.EndWorkKnowledge(workflow, cancellationToken);
                }
                else
                {
                    await _knowledgeDomainService.TerminateWorkKnowledge(workflow, cancellationToken);
                }
                break;
            case WorkflowModuleConsts.TelRestApply:
                await _telDomainService.TelRestApplyPassAsync(workflow.ExternalId, cancellationToken);
                break;
            case WorkflowModuleConsts.OrderHandle:
                var order = await _orderDomainService.GetOrderAsync(workflow.ExternalId,
                    withExtension: true, cancellationToken: cancellationToken);
                //order.CheckIfFiled();
                _mapper.Map(workflow, order);
                var now = DateTime.Now;
                var handleDuration = order.StartTime.HasValue
                    ? _timeLimitDomainService.CalcWorkTime(order.StartTime.Value,
                    now, order.ProcessType is EProcessType.Zhiban)
                    : 0;
                var fileDuration = order.CenterToOrgTime.HasValue
                    ? _timeLimitDomainService.CalcWorkTime(order.CenterToOrgTime.Value,
                        now, order.ProcessType is EProcessType.Zhiban)
                    : 0;
                var allDuration = order.StartTime.HasValue
                    ? _timeLimitDomainService.CalcWorkTime(order.StartTime.Value, now,
                    order.ProcessType is EProcessType.Zhiban)
                    : 0;
                order.File(now, handleDuration, fileDuration, allDuration);
                order.FileUserId = notification.Trace.HandlerId;
                order.FileUserName = notification.Trace.HandlerName;
                order.FileUserOrgId = notification.Trace.HandlerOrgId;
                order.FileUserOrgName = notification.Trace.HandlerOrgName;
                order.FileOpinion = notification.Trace.Opinion;

                //记录冗余归档数据
                if (notification.Workflow.Steps.Any(x => x.BusinessType == Share.Enums.FlowEngine.EBusinessType.Send))
                {
                    order.FileUserRole = EFileUserType.Dispatch;
                }
                else
                {
                    order.FileUserRole = EFileUserType.Seat;
                }
                if (order.ProcessType == EProcessType.Jiaoban)
                {
                    order.FileUserRole = EFileUserType.Org;
                }

                //是否已解决
                order.IsResolved = notification.External == null ? false : notification.External.IsResolved;

                await _orderRepository.UpdateAsync(order, cancellationToken);
                //var callRecord = await _trCallRecordRepository.GetAsync(p => p.CallAccept == order.CallId, cancellationToken); //由CallAccept改为OtherAccept
                var callRecord = await _trCallRecordRepository.GetAsync(p => p.OtherAccept == order.CallId, cancellationToken);
                var orderFlowDto = new OrderFlowDto
                {
                    Order = _mapper.Map<OrderDto>(order),
                    WorkflowTrace = _mapper.Map<WorkflowTraceDto>(notification.Trace)
                };
                if (callRecord != null)
                {
                    orderFlowDto.TrCallRecordDto = _mapper.Map<TrCallDto>(callRecord);
                }
                //这里需要判断是否是警情退回
                orderFlowDto.IsNonPoliceReturn = notification.External == null ? false : notification.External.IsPoliceReturn;
                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFiled, orderFlowDto, cancellationToken: cancellationToken);
                //写入质检  针对受理之后直接结束的工单
                await _qualityApplication.AddQualityAsync(EQualitySource.Accepted, order.Id, cancellationToken);

                //司法行政监督管理-工单处理
                await _enforcementApplication.AddEnforcementOrderAsync(order, cancellationToken);
                //推诿工单
               // await _enforcementApplication.AddPassTheBuckOrderAsync(order, _sessionContext.OrgId, _sessionContext.OrgName, cancellationToken);
                break;
            case WorkflowModuleConsts.OrderScreen:
                var screen = await _orderScreenRepository.GetAsync(workflow.ExternalId, cancellationToken);
                if (screen != null)
                {
                    screen.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
                    if (isReviewPass)
                    {
                        screen.Status = EScreenStatus.End;
                        screen.ReplyContent = workflow.ActualOpinion;
                        await _orderScreenRepository.UpdateAsync(screen, cancellationToken);
                        var visitDetail =
                            await _orderVisitedDetailRepository.GetAsync(screen.VisitDetailId, cancellationToken);
                        if (visitDetail != null)
                        {
                            var screenSatisfy = new Kv() { Key = "-1", Value = "视为满意" };
                            visitDetail.OrgProcessingResults = screenSatisfy;
                            //visitDetail.OrgHandledAttitude = screenSatisfy;
                            await _orderVisitedDetailRepository.UpdateAsync(visitDetail, cancellationToken);
                            // 修改主表当前评价结果
                            await _orderVisitRepository.Updateable().SetColumns(v => new OrderVisit() { NowEvaluate = screenSatisfy }).Where(v => v.Id == visitDetail.VisitId).ExecuteCommandAsync(cancellationToken);
                            //获取回访信息
                            var visit = await _orderVisitRepository.Queryable().Includes(x => x.Order)
                                .Includes(x => x.OrderVisitDetails)
                                .Where(x => x.Id == screen.VisitId).FirstAsync(cancellationToken);
                            if (visit != null)
                            {
                                //获取回访明细
                                var visitDe = visit.OrderVisitDetails.First(x => x.Id == screen.VisitDetailId);
                                //推省上
                                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderScreenApplyed,
                                      new PublishVisitDto()
                                      {
                                          Order = _mapper.Map<OrderDto>(visit.Order),
                                          No = visit.No,
                                          VisitType = visit.VisitType,
                                          VisitName = visit.CreatorName,
                                          VisitTime = visit.VisitTime,
                                          VisitRemark = string.IsNullOrEmpty(visitDe.VisitContent) ? screenSatisfy.Value : visitDe.VisitContent,
                                          AreaCode = visit.Order.AreaCode!,
                                          SubjectResultSatifyCode = visitDe.OrgProcessingResults?.Key,
                                          FirstSatisfactionCode = visit.Order.FirstVisitResultCode!,
                                          ClientGuid = ""
                                      });

                                //推门户
                                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisitedWeb, new PublishVisitAllDto()
                                {
                                    Id = visit.Id,
                                    Order = _mapper.Map<OrderDto>(visit.Order),
                                    OrderVisitDetails = _mapper.Map<List<VisitDetailDto>>(visit.OrderVisitDetails),
                                    VisitName = visit.CreatorName,
                                    VisitTime = visit.VisitTime,
                                    VisitType = visit.VisitType,
                                    VisitState = visit.VisitState,
                                    PublishTime = visit.PublishTime,
                                }, cancellationToken: cancellationToken);
                            }
                        }
                    }
                    else
                    {
                        await _orderRepository.OrderScreenRevisionVisit(screen.VisitId, true, cancellationToken);
                        screen.Status = EScreenStatus.Refuse;
                        screen.ReplyContent = workflow.ActualOpinion;
                        await _orderScreenRepository.UpdateAsync(screen, cancellationToken);
                    }
                }
                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);
                    if (isReviewPass)
                    {
                        delay.DelayState = isReviewPass ? EDelayState.Pass : EDelayState.NoPass;
                        await _orderDelayRepository.UpdateAsync(delay, cancellationToken);

                        //处理工单延期
                        await _orderApplication.DelayOrderExpiredTimeAsync(delay.OrderId, delay.DelayNum,
                            delay.DelayUnit, cancellationToken);
                    }
                    else
                    {
                        delay.DelayState = EDelayState.NoPass;
                        await _orderDelayRepository.UpdateAsync(delay, cancellationToken);
                    }
                }
                break;
        }
    }
}