using DotNetCore.CAP;
using Hotline.Application.CallCenter;
using Hotline.Application.JudicialManagement;
using Hotline.Application.Orders;
using Hotline.Caching.Interfaces;
using Hotline.CallCenter.Tels;
using Hotline.Configurations;
using Hotline.EventBus;
using Hotline.FlowEngine.Notifications;
using Hotline.FlowEngine.WorkflowModules;
using Hotline.JudicialManagement.Notifies;
using Hotline.KnowledgeBase;
using Hotline.Orders;
using Hotline.Settings;
using Hotline.Settings.TimeLimitDomain;
using Hotline.Settings.TimeLimits;
using Hotline.Share.Dtos.FlowEngine.Workflow;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Dtos.TrCallCenter;
using Hotline.Share.Enums.Order;
using MapsterMapper;
using MediatR;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
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<OrderDelay> _orderDelayRepository;
    // private readonly ITimeLimitDomainService _timeLimitDomainService;
    private readonly ILogger<WorkflowEndHandler> _logger;
    private readonly IKnowledgeRepository _knowledgeRepository;
    private readonly ICallApplication _callApplication;
    private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
    private readonly ISystemSettingCacheManager _systemSettingCacheManager;
    private readonly Publisher _publisher;
    private readonly ICalcExpireTime _expireTime;
    private readonly IRepository<OrderTerminate> _orderTerminateRepository;

	public WorkflowEndHandler(
        IMapper mapper,
        IKnowledgeDomainService knowledgeDomainService,
        IOrderDomainService orderDomainService,
        IOrderApplication orderApplication,
        ITelDomainService telDomainService,
        IOrderRepository orderRepository,
        IKnowledgeRepository knowledgeRepository,
        IRepository<OrderDelay> orderDelayRepository,
        ICapPublisher capPublisher,
        // ITimeLimitDomainService timeLimitDomainService,
        ICallApplication callApplication,
        IOptionsSnapshot<AppConfiguration> appOptions,
        ISystemSettingCacheManager systemSettingCacheManager,
        Publisher publisher,
        ILogger<WorkflowEndHandler> logger,
        ICalcExpireTime expireTime,
        IRepository<OrderTerminate> orderTerminateRepository)
    {
        _mapper = mapper;
        _knowledgeDomainService = knowledgeDomainService;
        _orderDomainService = orderDomainService;
        _orderApplication = orderApplication;
        _telDomainService = telDomainService;
        _orderRepository = orderRepository;
        _knowledgeRepository = knowledgeRepository;
        _orderDelayRepository = orderDelayRepository;
        _capPublisher = capPublisher;
        //_timeLimitDomainService = timeLimitDomainService;
        _callApplication = callApplication;
        _appOptions = appOptions;
        _systemSettingCacheManager = systemSettingCacheManager;
        _publisher = publisher;
        _logger = logger;
        _expireTime = expireTime;
        _orderTerminateRepository = orderTerminateRepository;
    }

    /// <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)
    {
        try
        {

            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 == workflow.ExternalId).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();
                    order.UpdateHandlingStatus(workflow.IsInCountersign);
                    _mapper.Map(workflow, order);
                    var now = DateTime.Now;
                    var handleDuration = order.CenterToOrgTime.HasValue && order.ActualHandleTime.HasValue
                        ? // _timeLimitDomainService.CalcWorkTime(
                        await _expireTime.CalcWorkTime(
                            order.CenterToOrgTime.Value,
                        order.ActualHandleTime.Value, order.ProcessType is EProcessType.Zhiban)
                        : 0;
                    var fileDuration = order.CenterToOrgTime.HasValue
                        ? //_timeLimitDomainService.CalcWorkTime(
                        await _expireTime.CalcWorkTime(
                            order.CenterToOrgTime.Value,
                            now, order.ProcessType is EProcessType.Zhiban)
                        : 0;
                    var allDuration = order.StartTime.HasValue
                        ? // _timeLimitDomainService.CalcWorkTime(
                        await _expireTime.CalcWorkTime(
                            order.StartTime.Value, now,
                        order.ProcessType is EProcessType.Zhiban)
                        : 0;
                    var creationTimeHandleDurationWorkday = order.ActualHandleTime.HasValue
                        ? //_timeLimitDomainService.CalcWorkTimeEx(
                        await _expireTime.CalcWorkTimeEx(
                            order.CreationTime, now,
                        order.ProcessType is EProcessType.Zhiban)
                        : 0;
                    var centerToOrgHandleDurationWorkday = order.ActualHandleTime.HasValue && order.CenterToOrgTime.HasValue
                        ? //_timeLimitDomainService.CalcWorkTimeEx(
                        await _expireTime.CalcWorkTimeEx(
                            order.CenterToOrgTime.Value, now,
                        order.ProcessType is EProcessType.Zhiban)
                        : 0;
                    creationTimeHandleDurationWorkday = creationTimeHandleDurationWorkday <= 0 ? 10 : creationTimeHandleDurationWorkday;
                    centerToOrgHandleDurationWorkday = centerToOrgHandleDurationWorkday <= 0 ? 10 : centerToOrgHandleDurationWorkday;

                    order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday);
                    order.FileUserId = notification.Trace.HandlerId;
                    order.FileUserName = notification.Trace.HandlerName;
                    order.FileUserOrgId = notification.Trace.HandlerOrgId;
                    order.FileUserOrgName = notification.Trace.HandlerOrgName;
                    order.FileOrgIsCenter = notification.Trace.HandlerOrgIsCenter;
                    order.FileOpinion = notification.Dto.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.Dto.External == null ? false : notification.Dto.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);
                    // }
                    if (order.SourceChannelCode == AppDefaults.SourceChannel.DianHua &&
                        !string.IsNullOrEmpty(order.CallId))
                    {
                        if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun)
                        {
                            // var callRecord = await _trCallRecordRepository.GetAsync(p => p.OtherAccept == order.CallId, cancellationToken);
                            var callRecord = await _callApplication.GetTianrunCallAsync(order.CallId, cancellationToken);
                            if (callRecord != null)
                            {
                                orderFlowDto.TrCallRecordDto = _mapper.Map<TrCallDto>(callRecord);
                            }
                        }
                        else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang)
                        {
                            var call = await _callApplication.GetCallAsync(order.CallId, cancellationToken);
                            if (call is not null)
                                orderFlowDto.TrCallRecordDto = _mapper.Map<TrCallDto>(call);
                        }
                    }

                    //这里需要判断是否是警情退回
                    orderFlowDto.IsNonPoliceReturn = notification.Dto.External == null ? false : notification.Dto.External.IsPoliceReturn;
                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFiled, orderFlowDto, cancellationToken: cancellationToken);

                    await _orderDomainService.OrderAutomaticPublishAsync(order, cancellationToken);
                    //try
                    //{
                    //    //写入质检  针对受理之后直接结束的工单
                    //    await _qualityApplication.AddQualityAsync(EQualitySource.Accepted, order.Id, cancellationToken);
                    //}
                    //catch (Exception e)
                    //{
                    //    _logger.LogError($"写入质检异常！orderId: {order.Id}, \r\n{e.Message}");
                    //}

                    //司法行政监督管理-工单处理
                    //如果没开启则不处理
                    var isOpenJudicialManagement = _systemSettingCacheManager.GetSetting(SettingConstants.IsOpenJudicialManagement)?.SettingValue[0];
                    if (isOpenJudicialManagement == "true")
                        await _publisher.PublishAsync(new JudicialManagementOrderNotify(order), PublishStrategy.ParallelWhenAll, 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;
                //               }
                //               screen.NewestAuditTime = DateTime.Now;
                //await _orderScreenRepository.UpdateAsync(screen, cancellationToken);
                //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 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, delay.IsProDelay, cancellationToken);
                        }
                        else
                        {
                            delay.DelayState = EDelayState.NoPass;
                            await _orderDelayRepository.UpdateAsync(delay, cancellationToken);
                        }
                    }
                    break;
                case WorkflowModuleConsts.OrderTerminate:
                    var orderTerminate = await _orderTerminateRepository.Queryable()
                        .Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
                    if (orderTerminate != null)
                    {
                        orderTerminate.Status = isReviewPass ? ETerminateStatus.End : ETerminateStatus.Refuse;
                        await _orderTerminateRepository.UpdateAsync(orderTerminate, cancellationToken);
                    }
                    break;
            }

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