using Hotline.Caching.Interfaces;
using Hotline.CallCenter.Calls;
using Hotline.CallCenter.Configs;
using Hotline.DI;
using Hotline.Realtimes;
using Hotline.Settings;
using Hotline.Share.Enums.CallCenter;
using Hotline.Share.Notifications.NewRockCallCenter;
using MediatR;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NewRock.Sdk;
using NewRock.Sdk.Transfer.Connect.Request;
using NewRock.Sdk.Transfer.Queue.Request;
using XF.Domain.Cache;
using XF.Domain.Constants;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.Application.Handlers.CallCenter.FlowControl
{
    [Injection(EventHandlerType = EEventHandlerType.CallCenter, Label = AppDefaults.CallCenterType.XunShi)]
    public class IncomingNotificationHandler : INotificationHandler<IncomingNotification>
    {
        private readonly ICallRepository _callRepository;
        private readonly ICallDetailRepository _callDetailRepository;
        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
        private readonly IIvrCacheManager _ivrCacheManager;
        private readonly INewRockClient _newRockClient;
        private readonly IOptionsSnapshot<CallCenterConfiguration> _options;
        private readonly ITypedCache<List<TrunkIvrManager>> _worktimeCache;
        private readonly ILogger<IncomingNotificationHandler> _logger;
        private readonly IRepository<TrunkIvrManager> _trunkIvrManagerRepository;
        private readonly ICallCacheManager _callCacheManager;
        private readonly IRealtimeService _realtimeService;

        public IncomingNotificationHandler(
            ICallRepository callRepository,
            ICallDetailRepository callDetailRepository,
            ISystemSettingCacheManager systemSettingCacheManager,
            IIvrCacheManager ivrCacheManager,
            INewRockClient newRockClient,
            IOptionsSnapshot<CallCenterConfiguration> options,
            ITypedCache<List<TrunkIvrManager>> worktimeCache,
            ILogger<IncomingNotificationHandler> logger,
            IRepository<TrunkIvrManager> trunkIvrManagerRepository,
            ICallCacheManager callCacheManager,
            IRealtimeService realtimeService)
        {
            _callRepository = callRepository;
            _callDetailRepository = callDetailRepository;
            _systemSettingCacheManager = systemSettingCacheManager;
            _ivrCacheManager = ivrCacheManager;
            _newRockClient = newRockClient;
            _options = options;
            _worktimeCache = worktimeCache;
            _logger = logger;
            _trunkIvrManagerRepository = trunkIvrManagerRepository;
            _callCacheManager = callCacheManager;
            _realtimeService = realtimeService;
        }

        public async Task Handle(IncomingNotification notification, CancellationToken cancellationToken)
        {
            var model = await _callRepository.GetAsync(
                x => x.ConversationId == notification.Visitor.Id && x.Trunk == notification.TrunkId &&
                     x.FromNo == notification.Visitor.From && x.CreationTime >= DateTime.Now.AddHours(-2), true, x => x.CreationTime, cancellationToken);
            if (model != null)
            {
                model.CallStatus = ECallStatus.Incoming;
                await _callRepository.UpdateAsync(model, cancellationToken);
                var detail = new CallDetail()
                {
                    CallId = model.Id,
                    CallStatus = ECallStatus.Incoming,
                    OMCallId = notification.Visitor.CallId,
                    ConversationId = notification.Visitor.Id,
                    EventName = notification.Attribute,
                    FromNo = notification.Visitor.From,
                    ToNo = notification.Visitor.To,
                };
                await _callDetailRepository.AddAsync(detail, cancellationToken);
                //TODO IVR处理
                var setting = _systemSettingCacheManager.GetSetting(SettingConstants.IVRConfig);
                if (bool.Parse(setting.SettingValue[0]))
                {
                    var correct = GetCorrectIvr(notification.Visitor.To);

                    //var ivr = GetCorrectIvr();


                    switch (correct.eCorrectIvr)
                    {
                        case ECorrectIvr.Ivr:

                            var ivrList = await _ivrCacheManager.GetIvrsAsync(cancellationToken);
                            if (!ivrList.Any())
                                throw new UserFriendlyException("未查到任何ivr配置");
                            var ivr = ivrList.First(x => x.IvrCategoryId == correct.ReturnValue && x.IsRoot);

                            _logger.LogInformation("transfer to ivr.no: {ivrNo}", ivr.No);
                            await _newRockClient.VisitorToMenu(
                                new VisitorToMenuRequest()
                                {
                                    Attribute = "Connect",
                                    Menu = new VisitorToMenuMenu() { Id = ivr.No },
                                    Visitor = new VisitorToMenuVisitor() { Id = notification.Visitor.Id }
                                },
                                _options.Value.NewRock.ReceiveKey, _options.Value.NewRock.Expired, cancellationToken);

                            //写入进入IVR流程
                            model.InIvrTime = DateTime.Now;
                            await _callRepository.UpdateAsync(model, cancellationToken);
                            var detailTwo = new CallDetail()
                            {
                                CallId = model.Id,
                                CallStatus = ECallStatus.InIvr,
                                OMCallId = notification.Visitor.CallId,
                                ConversationId = notification.Visitor.Id,
                                EventName = notification.Attribute,
                                FromNo = notification.Visitor.From,
                                ToNo = notification.Visitor.To,
                            };
                            await _callDetailRepository.AddAsync(detail, cancellationToken);

                            break;
                        case ECorrectIvr.Group:
                            _logger.LogInformation("transfer to group.no:{groupNo}", correct.ReturnValue);
                            await _newRockClient.VisitorToGroupQueue(new VisitorToGroupQueueRequest()
                            {
                                Attribute = "Queue",
                                Visitor = new VisitorToGroupQueueVisitor() { Id = notification.Visitor.Id },
                                Group = new VisitorToGroupQueueGroup() { Id = correct.ReturnValue }
                            },
                            _options.Value.NewRock.ReceiveKey, _options.Value.NewRock.Expired, cancellationToken);
                            model.InQueueTime = DateTime.Now;
                            await _callRepository.UpdateAsync(model, cancellationToken);
                            //处理队列记录
                            _callCacheManager.AddCallCache(model);
                            await _realtimeService.CallQueueAsync(_callCacheManager.GetCallQueueList(), cancellationToken);
                            break;
                        default:
                            //TODO 跳转默认分机组
                            break;
                    }
                }
                else
                {
                    //TODO 跳转默认分机组
                }
            }
        }

        private CorrectIvr GetCorrectIvr(string to)
        {
            var worktimeSettings = _worktimeCache.GetOrSet("worktimesettings", d =>
            {
                var settings = _trunkIvrManagerRepository.QueryAsync(x => x.IsEnable).GetAwaiter().GetResult();
                return settings;
            });
            var correct = GetCorrectCategory(worktimeSettings.First(x => x.TrunkId == to));
            return correct;
        }

        public class CorrectIvr
        {
            public string ReturnValue { get; set; }

            public ECorrectIvr eCorrectIvr { get; set; }
        }


        private CorrectIvr GetCorrectCategory(TrunkIvrManager settings)
        {
            if (!settings.WorkDay.Any(x => x.weekValue == ((int)DateTime.Now.DayOfWeek).ToString()))
                return new CorrectIvr() { eCorrectIvr = settings.RestCategory != "" ? ECorrectIvr.Ivr : ECorrectIvr.Group, ReturnValue = settings.RestCategory != "" ? settings.RestCategory : settings.RestToGroup };

            var time = TimeOnly.FromDateTime(DateTime.Now);
            if ((time >= TimeOnly.Parse(settings.MorningBegin) && time <= TimeOnly.Parse(settings.MorningEnd))
                || (time >= TimeOnly.Parse(settings.AfterBegin) && time <= TimeOnly.Parse(settings.AfterEnd))
                )
            {
                return new CorrectIvr() { eCorrectIvr = settings.WorkCategory != "" ? ECorrectIvr.Ivr : ECorrectIvr.Group, ReturnValue = settings.WorkCategory != "" ? settings.WorkCategory : settings.WorkToGroup };
            }
            else
            {
                return new CorrectIvr() { eCorrectIvr = settings.RestCategory != "" ? ECorrectIvr.Ivr : ECorrectIvr.Group, ReturnValue = settings.RestCategory != "" ? settings.RestCategory : settings.RestToGroup };
            }
        }
    }
}
