using DotNetCore.CAP;
using Hotline.Caching.Interfaces;
using Hotline.Identity.Accounts;
using Hotline.Push.Notifies;
using Hotline.Settings;
using Hotline.Share.Dtos.Push;
using Hotline.Share.Enums.Push;
using Hotline.Users;
using MapsterMapper;
using MediatR;
using XF.Domain.Cache;
using XF.Domain.Constants;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.Push
{
    public class MessageCodeDomainService : IMessageCodeDomainService, IScopeDependency
    {
        #region 注入
        private static readonly string KeyToken = "KeyFwLoginCode_" + DateTime.Now.ToString("yyyyMMdd") + "_";
        private readonly IMapper _mapper;
        private readonly IMediator _mediator;
        private readonly ICapPublisher _capPublisher;
        private readonly IAccountRepository _accountRepository;
        private readonly ITypedCache<LoginMessageCodeDto> _loginMessageCodeTypedCache;
        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
        private readonly IRepository<User> _userRepository;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="messageRepository"></param>
        /// <param name="mapper"></param>
        /// <param name="mediator"></param>
        /// <param name="messageTemplateRepository"></param>
        /// <param name="capPublisher"></param>
        public MessageCodeDomainService(IMapper mapper,
            IMediator mediator,
            ICapPublisher capPublisher, IAccountRepository accountRepository,
            ITypedCache<LoginMessageCodeDto> loginMessageCodeTypedCache,
            ISystemSettingCacheManager systemSettingCacheManager,
            IRepository<User> userRepository)
        {
            _mapper = mapper;
            _mediator = mediator;
            _capPublisher = capPublisher;
            _accountRepository = accountRepository;
            _loginMessageCodeTypedCache = loginMessageCodeTypedCache;
            _systemSettingCacheManager = systemSettingCacheManager;
            _userRepository = userRepository;
        }
        #endregion

        /// <summary>
        /// 验证白名单
        /// </summary>
        /// <param name="UserName"></param>
        /// <returns></returns>
        public async Task<bool> VerifyWhitelistAsync(string UserName)
        {
            var setting = _systemSettingCacheManager.GetSetting(SettingConstants.IsLoginMessageCode);
            if (setting == null || setting.SettingValue[0] != "true")
                return false;

            var settingWhite = _systemSettingCacheManager.GetSetting(SettingConstants.LoginCodeWhiteList);

            if (settingWhite == null || !settingWhite.SettingValue.Exists(p => p == UserName))
                return true;

            return false;
        }

        /// <summary>
        /// 生成验证码
        /// </summary>
        /// <param name="PhoneNum"></param>
        /// <returns></returns>
        public async Task<string> GenerateVerificationCode(string UserName, CancellationToken cancellation)
        {
            var setting = _systemSettingCacheManager.GetSetting(SettingConstants.IsLoginMessageCode);
            if (setting == null || setting.SettingValue[0] != "true")
                return "未开启短信验证！";

            var settingWhite = _systemSettingCacheManager.GetSetting(SettingConstants.LoginCodeWhiteList);
            if (settingWhite != null && settingWhite.SettingValue.Exists(p => p == UserName))
                return "账号不受限，请直接登录。";

            var account = await _accountRepository.GetExtAsync(d => d.UserName == UserName, d => d.Includes(x => x.Roles));
            if (account == null)
                return "用户名错误！";

            var userInfo = await _userRepository.GetAsync(p => p.Id == account.Id);
            if (userInfo == null || string.IsNullOrEmpty(userInfo.PhoneNo))
                return "用户未配置手机号码！";

            string strKeyToken = KeyToken + userInfo.PhoneNo;

            var token = await _loginMessageCodeTypedCache.GetAsync(strKeyToken, cancellation);
            if (token != null)
            {
                // 验证是否在5分钟之内
                TimeSpan duration = DateTime.Now - token.AddTime; // 计算时间差
                if ((int)duration.TotalSeconds < 300)
                    return "验证码在有效期！";

                token.AddTime = DateTime.Now;
            }
            else
            {
                token = new LoginMessageCodeDto
                {
                    Code = GetRandCode(6),
                    AddTime = DateTime.Now,
                    IsChecking = false
                };
            }

            var messageDto = new MessageDto
            {
                PushBusiness = EPushBusiness.MsgCode,
                PushPlatform = EPushPlatform.Sms,
                Name = account.Name,
                TemplateCode = "1006",
                Params = new List<string>() { token.Code },
                TelNumber = userInfo.PhoneNo,

            };
            await _mediator.Publish(new PushMessageNotify(messageDto), cancellation);

            //修改缓存
            await _loginMessageCodeTypedCache.SetAsync(strKeyToken, token, TimeSpan.FromDays(1), cancellation);

            return "验证码发送成功";
        }

        /// <summary>
        /// 校验验证码 
        /// </summary>
        /// <param name="PhoneNo"></param>
        /// <param name="Code"></param>
        /// <param name="cancellation"></param>
        /// <returns></returns>
        public async Task CheckdCode(string UserName, string PhoneNo, string Code, CancellationToken cancellation)
        {
            var setting = _systemSettingCacheManager.GetSetting(SettingConstants.IsLoginMessageCode);
            if (setting == null || setting.SettingValue[0] != "true")
                return;

            var settingWhite = _systemSettingCacheManager.GetSetting(SettingConstants.LoginCodeWhiteList);
            if (settingWhite != null && settingWhite.SettingValue.Exists(p => p == UserName))
                return;

            if (string.IsNullOrEmpty(Code))
                throw UserFriendlyException.SameMessage("验证码不能为空！");

            string strKeyToken = KeyToken + PhoneNo;
            var token = await _loginMessageCodeTypedCache.GetAsync(strKeyToken, cancellation);
            if (token == null)
                throw UserFriendlyException.SameMessage("验证码校验失败！");

            //if (token.IsChecking)
            //    return;

            if (string.IsNullOrEmpty(Code) || token.Code != Code)
                throw UserFriendlyException.SameMessage("验证码错误！");

            if (token != null)
            {
                token.IsChecking = true;
                //修改缓存
                await _loginMessageCodeTypedCache.SetAsync(strKeyToken, token, TimeSpan.FromDays(1), cancellation);
            }
        }

        /// <summary>
        /// 获取随机的6位密码（纯数字）
        /// </summary>
        /// <returns></returns>
        private string GetRandCode(int nLenth = 6)
        {
            Random random = new();
            string strNums = "";
            for (int i = 0; i < nLenth; i++)
            {
                strNums += random.Next(0, 9).ToString();
            }
            return strNums;
        }

    }
}
