using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Exceptions;
using Aliyun.Acs.Core.Profile;
using Furion;
using Furion.DatabaseAccessor;
using Furion.FriendlyException;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Ewide.Core.Util
{
    public class CodeHelper
    {
        private readonly IMemoryCache _IMemoryCache;
        private readonly IRepository<SysUser> _sysUserRep;  // 用户表仓储 
        private readonly IUserManager _userManager;

        public CodeHelper(
            IMemoryCache IMemoryCache, 
            IRepository<SysUser> sysUserRep,
            IUserManager userManager
            ){
            _IMemoryCache = IMemoryCache;
            _sysUserRep = sysUserRep;
            _userManager = userManager;
        }
        public static string Aliyun_AccessKey = App.Configuration["SmsHelper:Aliyun_AccessKey"];
        public static string Aliyun_AccessSecret = App.Configuration["SmsHelper:Aliyun_AccessSecret"];
        public static string Aliyun_Smscode_SignName = App.Configuration["SmsHelper:Aliyun_Smscode_SignName"];
        public static string Aliyun_Smscode_TemplateCode = App.Configuration["SmsHelper:Aliyun_Smscode_TemplateCode"];

        /// <summary>
        /// 发送验证码间隔时间(秒)
        /// </summary>
        protected static int code_Countdown = 60;

        /// <summary>
        ///  验证code
        /// </summary>
        protected static string Orgcode_Key = "ewide_Orgcode";

        ///<summary>
        ///邮箱Code
        /// </summary>
        protected static string mailcode_Key = "ewide_mailcode";

        ///<summary>
        ///手机Code
        /// </summary>
        protected static string smscode_Key = "ewide_smscode";

        /// <summary>
        /// 将code存入缓存
        /// </summary>
        /// <param name="way">验证方式</param>
        /// <param name="code">验证码</param>
        /// <param name="type">code的类型</param>
        public void Updatecode(string num, int code, string way)
        {
            
            var ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            _IMemoryCache.Set(
                way + "_" + num, // code的类型_手机或者邮箱号码
                code + "_" + (int)ts.TotalSeconds, // 1234567_TimeStamp
                DateTime.UtcNow.AddMinutes(5)// 5分钟过期
            );
        }

        /// <summary>
        /// 判断是否含有code
        /// </summary>
        /// <param name="way"></param>
        /// <param name="code"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public bool Checkcode(string Target, int? code,string Key)
        {
            var cache = (string)_IMemoryCache.Get(Key + "_" + Target);// 获取匹配类型的code值
            if (string.IsNullOrEmpty(cache))
            {
                return false;
            }
            return code == cache.Split('_').Select(p => int.Parse(p)).First();
        }

        /// <summary>
        /// 判断是否含有code
        /// </summary>
        /// <param name="way"></param>
        /// <param name="code"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public bool Checkhavecode(string num, string way)
        {
            var cache = (string)_IMemoryCache.Get(way + "_" + num);// 获取匹配类型的code值
            if (string.IsNullOrEmpty(cache))
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 删除相应缓存
        /// </summary>
        /// <param name="way"></param>
        /// <param name="type"></param>
        public void removecode(string way, string num){
            _IMemoryCache.Remove(way + "_" + num); 
        }

        /// <summary>
        /// code60秒才可再次发送
        /// </summary>
        /// <param name="way">验证类型</param>
        /// <param name="num">值</param>
        /// <param name="coundown"></param>
        /// <returns></returns>
        public bool IscodeCountdown(string way, string num, int coundown = 60)
        {
            return GetSmscodeCountdown(way, num) < coundown;
        }

        /// <summary>
        /// 发送验证码倒计时
        /// </summary>
        /// <param name="mobile"></param>
        /// <returns></returns>
        public int GetSmscodeCountdown(string way,string num)
        {
            var cache = (string)_IMemoryCache.Get(way + "_" + num);
            if (String.IsNullOrEmpty(cache))
            {
                return code_Countdown;
            }
            var ts = cache.Split('_').Select(p => int.Parse(p)).Last();
            var nowTs = (int)(DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds;
            return nowTs - ts;
        }

        ///<summary>
        /// 发送手机验证码
        ///</summary>
        public bool SendSmscode(string mobile, string way ,int length = 6)
        {
            if (!new Regex(@"^((13[0-9])|(14[5,7])|(15[^4,\\D])|(17[0,1,3,6-8])|(18[0-9])|(19[8,9])|(166))[0-9]{8}$").IsMatch(mobile))
            {
                throw Oops.Oh(ErrorCode.D1011);
            }
            //if (IscodeCountdown(way, mobile, code_Countdown))
            //{
            //    throw Oops.Oh(ErrorCode.D1023);
                
            //}

            IClientProfile profile = DefaultProfile.GetProfile("cn-hangzhou", Aliyun_AccessKey, Aliyun_AccessSecret);
            DefaultAcsClient client = new DefaultAcsClient(profile);
            CommonRequest request = new CommonRequest
            {
                Method = Aliyun.Acs.Core.Http.MethodType.POST,
                Domain = "dysmsapi.aliyuncs.com",
                Version = "2017-05-25",
                Action = "SendSms"
            };
            request.AddQueryParameters("PhoneNumbers", mobile);
            request.AddQueryParameters("SignName", Aliyun_Smscode_SignName);
            request.AddQueryParameters("TemplateCode", Aliyun_Smscode_TemplateCode);

            var minValue = Convert.ToInt32("1".PadRight(length, '0'));
            var maxValue = Convert.ToInt32("1".PadRight(length + 1, '0'));
            var code = new Random().Next(minValue, maxValue);
            var param = new { code };
            request.AddQueryParameters("TemplateParam", JsonConvert.SerializeObject(param));
            Updatecode(mobile, code,way);
            try
            {
                CommonResponse response = client.GetCommonResponse(request);
                var msg = System.Text.Encoding.UTF8.GetString(response.HttpResponse.Content);
                var result = JsonConvert.DeserializeObject(msg);
                var j = (JObject)result;
                if(!"OK".Equals(j["Code"].ToString(), StringComparison.CurrentCultureIgnoreCase))
                {
                    throw Oops.Oh("请不要频繁发送");
                }
                return true;
            }
            catch (ServerException e)
            {
                throw Oops.Oh(ErrorCode.D1024);
            }catch(Exception e)
            {
                throw Oops.Oh("访问异常");
            }
        }

        /// <summary>
        /// 发送邮箱
        /// </summary>
        /// <param name="mail"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public bool SendMail(string mail, string way,int length = 6)
        {
            if (!new Regex(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$").IsMatch(mail))
            {
                throw Oops.Oh("格式不对");
            }
            if (IscodeCountdown(mail, way, code_Countdown))
            {
                throw Oops.Oh("60秒后才能再次发送");
                
            }
            string account = App.Configuration["Mail:Account"];
            string passWord = App.Configuration["Mail:PassWord"];
            //var options = Options.Create(options: new MemoryCacheOptions());
            //IMemoryCache cache = new MemoryCache(options);
            SmtpClient smtpClient = new SmtpClient();
            smtpClient.EnableSsl = true;
            smtpClient.UseDefaultCredentials = false;
            smtpClient.Host = App.Configuration["Mail:Host"];
            smtpClient.Credentials = new System.Net.NetworkCredential(account, passWord);
            smtpClient.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;

            MailMessage mailMessage = new MailMessage();
            MailAddress fromAddr = new MailAddress(account);
            mailMessage.From = fromAddr;          
            mailMessage.To.Add(mail);
            mailMessage.Subject = App.Configuration["Mail:Subject"];
            mailMessage.BodyEncoding = Encoding.UTF8;
            mailMessage.IsBodyHtml = true;
            mailMessage.Priority = MailPriority.Low;
            var minValue = Convert.ToInt32("1".PadRight(length, '0'));
            var maxValue = Convert.ToInt32("1".PadRight(length + 1, '0'));
            var code = new Random().Next(minValue, maxValue);
            var param = new { code };
            Updatecode(mail, code, way);
            try
            {
                var Message = "邮箱验证码为:" + code.ToString();
                mailMessage.Body = Message;
                smtpClient.Send(mailMessage);
   
                return true;
            }
            catch
            {
                throw Oops.Oh(ErrorCode.xg1100);
            }
        }

        /// <summary>
        /// 检测是否重复
        /// </summary>
        /// <param name="Target"></param>
        /// <returns></returns>
        public async Task<bool> CheckRepeat(string Target)
        {
            var Regex_phone = @"^((13[0-9])|(14[5,7])|(15[^4,\\D])|(17[0,1,3,6-8])|(18[0-9])|(19[8,9])|(166))[0-9]{8}$";
            var Regex_Email = @"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$";
            if(new Regex(Regex_phone).IsMatch(Target)){
                var isExist = await _sysUserRep.DetachedEntities.AnyAsync(u => (u.Id != _userManager.UserId ) && (u.Account == Target || u.Phone == Target));
                if (isExist) throw Oops.Oh("手机号与他人账号或者手机号重复");
            }else if(new Regex(Regex_Email).IsMatch(Target))
            {
                var isExist3 = await _sysUserRep.DetachedEntities.AnyAsync(u => (u.Id != _userManager.UserId) && (u.Account == Target || u.Email == Target));
                if (isExist3) throw Oops.Oh("邮箱与他人账号或者邮箱重复");
            }
            return true;
        }
    }
}
