using DotNetCore.CAP;
using Hotline.Application.CallCenter;
using Hotline.Application.Quality;
using Hotline.Caching.Interfaces;
using Hotline.Configurations;
using Hotline.FlowEngine.Notifications;
using Hotline.FlowEngine.WorkflowModules;
using Hotline.KnowledgeBase;
using Hotline.Orders;
using Hotline.Push.Notifies;
using Hotline.Settings;
using Hotline.Share.Dtos.FlowEngine.Workflow;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Dtos.TrCallCenter;
using Hotline.Share.Enums.CallCenter;
using Hotline.Share.Enums.FlowEngine;
using Hotline.Share.Enums.Push;
using Hotline.Share.Enums.Quality;
using Hotline.Share.Mq;
using Hotline.Share.Tools;
using Hotline.Users;
using MapsterMapper;
using MediatR;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using XF.Domain.Repository;

namespace Hotline.Application.Handlers.FlowEngine
{
    public class WorkflowStartHandler : INotificationHandler<StartWorkflowNotify>
    {
        private readonly IOrderDomainService _orderDomainService;
        private readonly IKnowledgeDomainService _knowledgeDomainService;
        private readonly IOrderRepository _orderRepository;
        private readonly ICapPublisher _capPublisher;
        private readonly IMapper _mapper;
        private readonly ILogger<WorkflowStartHandler> _logger;
        private readonly IQualityApplication _qualityApplication;
        // private readonly IRepository<TrCallRecord> _trCallRecordRepository;
        private readonly IOrderDelayRepository _orderDelayRepository;
        private readonly IRepository<User> _userRepository;
        private readonly ICallApplication _callApplication;
        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
        private readonly IMediator _mediator;
        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
        private readonly IRepository<OrderTerminate> _orderTerminateRepository;

        public WorkflowStartHandler(
            IOrderDomainService orderDomainService,
            IKnowledgeDomainService knowledgeDomainService,
            IOrderRepository orderRepository,
            ICapPublisher capPublisher,
            IQualityApplication qualityApplication,
            IMapper mapper,
            ILogger<WorkflowStartHandler> logger,
            IOrderDelayRepository orderDelayRepository,
            IRepository<User> userRepository,
            ICallApplication callApplication,
            IOptionsSnapshot<AppConfiguration> appOptions,
            IMediator mediator,
            ISystemSettingCacheManager systemSettingCacheManager,
            IRepository<OrderTerminate> orderTerminateRepository
        )
        {
            _orderDomainService = orderDomainService;
            _knowledgeDomainService = knowledgeDomainService;
            _orderRepository = orderRepository;
            _capPublisher = capPublisher;
            _qualityApplication = qualityApplication;
            _mapper = mapper;
            _logger = logger;
            // _trCallRecordRepository = trCallRecordRepository;
            _orderDelayRepository = orderDelayRepository;
            _userRepository = userRepository;
            _callApplication = callApplication;
            _appOptions = appOptions;
            _mediator = mediator;
            _systemSettingCacheManager = systemSettingCacheManager;
            _orderTerminateRepository = orderTerminateRepository;
        }

        /// <summary>Handles a notification</summary>
        /// <param name="notification">The notification</param>
        /// <param name="cancellationToken">Cancellation token</param>
        public async Task Handle(StartWorkflowNotify notification, CancellationToken cancellationToken)
        {
            try
            {
                //基础拉丁字母和中日韩统一表意文字的基础Unicode 块(U+4E00-U+9FCC)。 基本涵盖了除使用西里尔字母以外所有西方国家的文字和亚洲中日韩越的文字
                _logger.LogInformation(
                    //$"收到{nameof(StartWorkflowNotify)}, notification: {JsonSerializer.Serialize(notification, new JsonSerializerOptions { Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.CjkUnifiedIdeographs) })}");
                    $"收到{nameof(StartWorkflowNotify)}, workflowId: {notification.Workflow.Id}");
                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);
                        order.CheckIfFiled();
                        //order.StartManageFlow();
                        order.UpdateHandlingStatus(workflow.IsInCountersign);
                        _mapper.Map(workflow, order);
                        await _orderRepository.UpdateAsync(order, cancellationToken);

                        var publishCallRecordDto = new PublishCallRecrodDto() { };
                        //查询通话记录
                        //var callRecord = await _trCallRecordRepository.GetAsync(p => p.CallAccept == order.CallId, cancellationToken); //由CallAccept改为OtherAccept
                        // var callRecord = await _trCallRecordRepository.GetAsync(p => p.OtherAccept == order.CallId, cancellationToken);
                        // if (callRecord != null)
                        // {
                        //     publishCallRecordDto.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)
                                {
                                    publishCallRecordDto.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)
                                {
                                    publishCallRecordDto.TrCallRecordDto = _mapper.Map<TrCallDto>(call);

                                    // 工单开始办理如果获取的通话记录是呼出并且录音文件是空就不推送通话记录
                                    // 如果 通话记录是呼入, 并且没有录音文件
                                    if (_systemSettingCacheManager.OrderStartHandlerPushCallIsNull && call.Direction == ECallDirection.Out && call.AudioFile.IsNullOrEmpty())
                                    {
                                        publishCallRecordDto.TrCallRecordDto = null;
                                    }
                                }
                            }
                        }

                        publishCallRecordDto.Order = _mapper.Map<OrderDto>(order);
                        publishCallRecordDto.WorkflowTrace = _mapper.Map<WorkflowTraceDto>(notification.Trace);

                        await _capPublisher.PublishAsync(EventNames.HotlineOrderFlowStarted, publishCallRecordDto,
                            cancellationToken: cancellationToken);

                        try
                        {
                            if (notification.Dto.IsSms)
                            {
                                switch (notification.Trace.FlowAssignType)
                                {
                                    case EFlowAssignType.Org:
                                        var orgCodes = notification.Trace.NextHandlers.Select(x => x.OrgId); //notification.FlowAssignInfo.HandlerObjects.Select(x => x.Key);
                                        var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
                                        var orgList = await _userRepository.Queryable().Where(x =>
                                            orgCodes.Contains(x.OrgId) && x.Roles.Any(d => orgCodes.Contains(d.Id))).ToListAsync();
                                        foreach (var item in orgList)
                                        {
                                            if (!string.IsNullOrEmpty(item.PhoneNo))
                                            {
                                                var messageDto = new Share.Dtos.Push.MessageDto
                                                {
                                                    PushBusiness = EPushBusiness.OrderSupervise,
                                                    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.Trace.NextHandlers.Select(x => x.UserId); //notification.FlowAssignInfo.HandlerObjects.Select(x => x.Key);
                                        var userList = await _userRepository.Queryable().Where(x =>
                                            userCodes.Contains(x.Id) && !string.IsNullOrEmpty(x.PhoneNo)).ToListAsync();
                                        foreach (var item in userList)
                                        {
                                            var messageDto = new Share.Dtos.Push.MessageDto
                                            {
                                                PushBusiness = EPushBusiness.OrderSupervise,
                                                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 (Exception e)
                        {
                            _logger.LogError($"发送短信失败! orderId: {order.Id}，\r\n{e.Message}");
                        }

                        try
                        {
                            //写入质检
                            await _qualityApplication.AddQualityAsync(EQualitySource.Accepted, order.Id, cancellationToken);
                        }
                        catch (Exception e)
                        {
                            _logger.LogError($"写入质检异常！orderId: {order.Id}, \r\n{e.Message}");
                        }
                        break;
                    case WorkflowModuleConsts.KnowledgeAdd:
                    case WorkflowModuleConsts.KnowledgeUpdate:
                    case WorkflowModuleConsts.KnowledgeDelete:
                    case WorkflowModuleConsts.KnowledgeOffshelf:
                        await _knowledgeDomainService.UpdateWorkFlowId(workflow.ExternalId, workflow.Id,
                            workflow.HandlerUsers, workflow.HandlerOrgs, workflow.FlowedUserIds, workflow.FlowedOrgIds,
                            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.WorkflowId = workflow.Id;
                    //        screen.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
                    //        await _orderScreenRepository.UpdateAsync(screen, cancellationToken);
                    //    }

                    //    break;
                    case WorkflowModuleConsts.OrderDelay:
                        var orderDelay = await _orderDelayRepository.Queryable()
                            .Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
                        if (orderDelay != null)
                        {
                            orderDelay.WorkflowId = workflow.Id;
                            orderDelay.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
                            await _orderDelayRepository.UpdateAsync(orderDelay, cancellationToken);
                        }

                        break;
                    case WorkflowModuleConsts.OrderTerminate:
                        var orderTerminate = await _orderTerminateRepository.Queryable()
                            .Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
                        if (orderTerminate != null)
                        {
                            orderTerminate.WorkflowId = workflow.Id;
                            orderTerminate.Status = ETerminateStatus.Approval;
                            await _orderTerminateRepository.UpdateAsync(orderTerminate, cancellationToken);
                        }
                        break;
                }

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