using Hotline.Caching.Interfaces;
using Hotline.CallCenter.Configs;
using Hotline.CallCenter.Devices;
using Hotline.Configurations;
using Hotline.Settings;
using Hotline.Share.Dtos.CallCenter;
using Hotline.Share.Enums.CallCenter;
using MapsterMapper;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using XF.Domain.Cache;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.CallCenter.Ivrs;

public class IvrDomainService : IIvrDomainService, IScopeDependency
{
    private readonly INewRockDeviceManager _newRockDeviceManager;
    private readonly IIvrRepository _ivrRepository;
    private readonly ITypedCache<List<Ivr>> _cacheIvrList;
    private readonly IIvrCacheManager _ivrCacheManager;
    private readonly ITelCacheManager _telCacheManager;
    private readonly IUserCacheManager _userCacheManager;
    private readonly IMapper _mapper;
    private readonly ILogger<IvrDomainService> _logger;
    private readonly ITypedCache<List<TrunkIvrManager>> _worktimeCache;
    private readonly IOptionsSnapshot<CallCenterConfiguration> _callcenterOptions;
    private readonly IRepository<TrunkIvrManager> _trunkIvrManagerRepository;

    public IvrDomainService(
        IServiceProvider serviceProvider,
        IIvrRepository ivrRepository,
        ITypedCache<List<Ivr>> cacheIvrList,
        IIvrCacheManager ivrCacheManager,
        ITelCacheManager telCacheManager,
        IUserCacheManager userCacheManager,
        IMapper mapper,
        ILogger<IvrDomainService> logger,
        ITypedCache<List<TrunkIvrManager>> worktimeCache,
        IOptionsSnapshot<AppConfiguration> appOptions,
        IOptionsSnapshot<CallCenterConfiguration> callcenterOptions,
        IRepository<TrunkIvrManager> trunkIvrManagerRepository)
    {
        _ivrRepository = ivrRepository;
        _cacheIvrList = cacheIvrList;
        _ivrCacheManager = ivrCacheManager;
        _telCacheManager = telCacheManager;
        _userCacheManager = userCacheManager;
        _mapper = mapper;
        _logger = logger;
        _worktimeCache = worktimeCache;
        _callcenterOptions = callcenterOptions;
        _trunkIvrManagerRepository = trunkIvrManagerRepository;
        if (appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XunShi)
        {
            _newRockDeviceManager = serviceProvider.GetRequiredService<INewRockDeviceManager>();
        }
    }

    /// <summary>
    /// 语音播放结束
    /// </summary>
    /// <param name="menuId"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task<IvrAnswer?> GetVoiceEndAnswerAsync(string menuId, CancellationToken cancellationToken = default)
    {
        var ivrs = await _ivrCacheManager.GetIvrsAsync(cancellationToken);
        if (!ivrs.Any())
            throw new UserFriendlyException("未查到任何ivr配置");
        var ivr = ivrs.FirstOrDefault(d => d.No == menuId);
        if (ivr is null)
            throw new UserFriendlyException("未知语音菜单编号");
        var strategy = ivr.IvrStrategies.FirstOrDefault(d => d.IvrStrategeType == EIvrStrategeType.VoiceEnd);

        var answer = await ValuationStrategyAnswer(strategy, ivr, cancellationToken);
        _logger.LogInformation("语音播放结束响应策略: type: {type}, content: {content}, preVoice: {voice}", answer?.IvrAnswerTypeText, answer?.Content, answer?.PreVoice);
        return answer;
    }

    /// <summary>
    /// 获得按键输入
    /// </summary>
    /// <param name="menuId"></param>
    /// <param name="input"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task<IvrAnswer?> GetDtmfAnswerAsync(string menuId, string input, CancellationToken cancellationToken = default)
    {
        var ivrs = await _ivrCacheManager.GetIvrsAsync(cancellationToken);
        if (!ivrs.Any())
            throw new UserFriendlyException("未查到任何ivr配置");
        if (string.IsNullOrEmpty(input))
            throw new UserFriendlyException("无效输入参数");
        var ivr = ivrs.FirstOrDefault(d => d.No == menuId);
        if (ivr is null)
            throw new UserFriendlyException("未知语音菜单编号");
        if (input.Length > ivr.InfoLength)
            throw new UserFriendlyException("按键输入内容超出配置允许长度");

        IvrAnswer? answer;
        //超时
        if (input.EndsWith('T'))
        {
            var overTimeStrategy = ivr.IvrStrategies.FirstOrDefault(d => d.IvrStrategeType == EIvrStrategeType.OverTime);
            if (overTimeStrategy is null)
            {
                answer = new IvrAnswer { IvrAnswerType = EIvrAnswerType.HangUp };
                _logger.LogInformation($"未配置IVR超时策略, menuId: {menuId}");
                return answer;
            }

            overTimeStrategy.Answer.PreVoice = GetStrategyVoice(overTimeStrategy, ivr);
            answer = overTimeStrategy.Answer;
            _logger.LogInformation("按键响应策略: type: {type}, content: {content}, preVoice: {voice}", answer?.IvrAnswerTypeText, answer?.Content, answer?.PreVoice);
            return answer;
        }

        var inputValue = input;
        if (!string.IsNullOrEmpty(ivr.Exit) && input.EndsWith(ivr.Exit))
        {
            var length = ivr.Exit.Length;
            inputValue = input.Remove(input.Length - length, length);
        }

        if (ivr.IvrType == EIvrType.Normal)
        {
            var strategy = ivr.IvrStrategies.FirstOrDefault(d => d.Input == inputValue);
            answer = await ValuationStrategyAnswer(strategy, ivr, cancellationToken);
            _logger.LogInformation("按键响应策略: type: {type}, content: {content}, preVoice: {voice}", answer?.IvrAnswerTypeText, answer?.Content, answer?.PreVoice);
            return answer;
        }
        else if (ivr.IvrType == EIvrType.Score)//score
        {
            //todo 评分

            //评分成功返回第一个策略,否则直接挂机
            return ivr.IvrStrategies.FirstOrDefault()?.Answer ?? new IvrAnswer { IvrAnswerType = EIvrAnswerType.HangUp };
        }
        else
        {
            throw new ArgumentOutOfRangeException("无效IvrType");
        }
    }

    private async Task<IvrAnswer?> ValuationStrategyAnswer(IvrStrategy? strategy, Ivr ivr, CancellationToken cancellationToken)
    {
        if (strategy is null)
        {
            var errorStrategy = ivr.IvrStrategies.FirstOrDefault(d => d.IvrStrategeType == EIvrStrategeType.Error);
            return errorStrategy?.Answer ?? null;
        }

        if (strategy.IvrStrategeType == EIvrStrategeType.PreStep)
        {
            strategy.Answer.Content = ivr.PrevIvrNo;
            strategy.Answer.PreVoice = null;
        }

        if (strategy.Answer.IvrAnswerType == EIvrAnswerType.TelGroup)
        {
            var groupNo = await GetCurrentTelGroupAsync(strategy, cancellationToken);
            if (string.IsNullOrEmpty(groupNo)) return null;
            strategy.Answer.Content = groupNo;
        }
        return strategy.Answer;
    }

    public async Task<string> AddIvrAsync(Ivr ivr, CancellationToken cancellationToken = default)
    {
        var existNo = await _ivrRepository.AnyAsync(d => d.No == ivr.No, cancellationToken);
        if (existNo)
            throw new UserFriendlyException("IVR编号已存在");

        await _newRockDeviceManager.AssginConfigMenuAsync(_callcenterOptions.Value.NewRock, ivr.No, ivr.Voice, ivr.Repeat.ToString(), ivr.InfoLength.ToString(), ivr.Exit, cancellationToken);

        var exists = await _ivrRepository.AnyAsync(d => d.IvrCategoryId == ivr.IvrCategoryId, cancellationToken);
        ivr.IsRoot = !exists;
        var id = await _ivrRepository.AddAsync(ivr, cancellationToken);
        _cacheIvrList.Remove(Ivr.Key);
        return id;
    }

    public async Task UpdateIvrAsync(Ivr ivr, CancellationToken cancellationToken = default)
    {
        await _newRockDeviceManager.AssginConfigMenuAsync(_callcenterOptions.Value.NewRock, ivr.No, ivr.Voice, ivr.Repeat.ToString(), ivr.InfoLength.ToString(), ivr.Exit, cancellationToken);

        await _ivrRepository.UpdateWithoutStrategiesAsync(ivr, cancellationToken);
        _cacheIvrList.Remove(Ivr.Key);
    }

    /// <summary>
    /// 构建IVR关系
    /// </summary>
    /// <param name="dto"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task StructureIvrAsync(StructureIvrDto dto, CancellationToken cancellationToken)
    {
        var ivr = await _ivrRepository.GetAsync(dto.Id, cancellationToken);
        if (ivr == null)
            throw new UserFriendlyException("无效IVR编号");
        //if (!ivr.IsRoot && string.IsNullOrEmpty(dto.PrevIvrNo))
        //    throw new UserFriendlyException("上级IVR编号不能为空");

        //转下级IVR
        if (dto.IvrStrategies.Any(d => d.Answer.IvrAnswerType == EIvrAnswerType.Voice))
        {
            var voiceStrategy = dto.IvrStrategies.First(d => d.Answer.IvrAnswerType == EIvrAnswerType.Voice);
            if (string.IsNullOrEmpty(voiceStrategy.Answer.Content))
                throw new UserFriendlyException("未正确配置下一级IVR");
            var nextIvr = await _ivrRepository.GetAsync(d => d.No == voiceStrategy.Answer.Content);
            if (nextIvr == null)
                throw new UserFriendlyException("无效IVRNo");
            //支持插播语音以后转回自身
            if (nextIvr.No != ivr.No)
            {
                nextIvr.PrevIvrNo = ivr.No;
                await _ivrRepository.UpdateAsync(nextIvr, cancellationToken);
            }
        }

        //转分机组置空content
        if (dto.IvrStrategies.Any(d => d.Answer.IvrAnswerType == EIvrAnswerType.TelGroup))
        {
            var groupStrategy = dto.IvrStrategies.First(d => d.Answer.IvrAnswerType == EIvrAnswerType.TelGroup);
            groupStrategy.Answer.Content = null;
        }

        _mapper.Map(dto, ivr);
        await _ivrRepository.UpdateAsync(ivr, cancellationToken);
        _cacheIvrList.Remove(Ivr.Key);
    }

    /// <summary>
    /// 删除IVR关系（并非删除IVR）
    /// </summary>
    /// <param name="ivrId"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task DeStructureIvrAsync(string ivrId, CancellationToken cancellationToken)
    {
        var ivr = await _ivrRepository.GetAsync(ivrId, cancellationToken);
        if (ivr == null)
            throw new UserFriendlyException("无效IVR编号");
        ivr.PrevIvrNo = null;
        ivr.IvrStrategies = new();
        await _ivrRepository.UpdateAsync(ivr, false, cancellationToken);
    }

    /// <summary>
    /// 替换某个IVR分组下的起始IVR(根节点)
    /// </summary>
    /// <param name="ivrId"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task ReplaceRootAsync(string ivrId, CancellationToken cancellationToken)
    {
        var ivr = await _ivrRepository.GetAsync(ivrId, cancellationToken);
        if (ivr == null)
            throw new UserFriendlyException("无效IVR编号");
        var root = await _ivrRepository.GetAsync(d => d.IvrCategoryId == ivr.IvrCategoryId && d.IsRoot, cancellationToken);
        if (root == null)
            throw new UserFriendlyException($"异常起始IVR, IvrCategoryId: {ivr.IvrCategoryId}");
        root.IsRoot = false;
        ivr.IsRoot = true;
        ivr.PrevIvrNo = null;
        await _ivrRepository.UpdateAsync(ivr, false, cancellationToken);
        await _ivrRepository.UpdateAsync(root, cancellationToken);
    }

    #region private

    private async Task<string?> GetCurrentTelGroupAsync(IvrStrategy strategy, CancellationToken cancellationToken)
    {
        if (!strategy.GroupSorts.Any())
            return null;
        foreach (var groupSort in strategy.GroupSorts.OrderBy(d => d.Sort))
        {
            var group = _telCacheManager.GetTelGroup(groupSort.GroupNo);
            if (!group.Tels.Any()) continue;
            foreach (var tel in group.Tels)
            {
                var working = await _userCacheManager.IsWorkingByTelAsync(tel.No, cancellationToken);
                if (working)
                    return group.No;
            }
        }

        return null;
    }

    private string? GetStrategyVoice(IvrStrategy strategy, Ivr ivr)
    {
        return !string.IsNullOrEmpty(strategy.Answer.PreVoice) ? $"{strategy.Answer.PreVoice}+{ivr.Voice}" : null;
    }

    #endregion

    #region IVR流程处理


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

        public ECorrectIvr eCorrectIvr { get; set; }
    }

    public CorrectIvr GetCorrectIvr(string to, bool isEvaluate = false)
    {
        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), isEvaluate);
        return correct;
    }

    private CorrectIvr GetCorrectCategory(TrunkIvrManager settings, bool isEvaluate)
    {
        if (isEvaluate)
        {
            return new CorrectIvr() { eCorrectIvr = ECorrectIvr.Ivr, ReturnValue = settings.EvaluateCategory };
        }

        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 };
        }
    }


    #endregion
}