using Furion.DataEncryption;
using Furion.DependencyInjection;
using Nirvana.Common;
using Nirvana.Common.ApiBase;
using Senparc.Weixin;
using Senparc.Weixin.WxOpen.AdvancedAPIs.Sns;
using Senparc.Weixin.WxOpen.Containers;
using Senparc.Weixin.WxOpen.Helpers;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using YBDevice.Core;
using YBDevice.Entity;

namespace YBDevice.NApi.Application.BusinessClient.AccountInfo
{
    public class AccountService : IAccountService, ITransient
    {
        public string WxOpenAppId = Senparc.Weixin.Config.SenparcWeixinSetting.WxOpenAppId;
        public string WxOpenAppSecret = Senparc.Weixin.Config.SenparcWeixinSetting.WxOpenAppSecret;
        public string WxOpenToken = Senparc.Weixin.Config.SenparcWeixinSetting.WxOpenToken;
        public string WxOpenEncodingAESKey = Senparc.Weixin.Config.SenparcWeixinSetting.WxOpenEncodingAESKey;
        private readonly ISqlSugarRepository<YB_OfficlaAccount> repository;
        private readonly SqlSugarClient dbClient;
        private readonly ILoggerService _loggerService;
        private readonly IHttpClientFactory _clientFactory;
        public AccountService(ISqlSugarRepository<YB_OfficlaAccount> sqlSugarRepository, ILoggerService loggerService, IHttpClientFactory clientFactory)

        {
            repository = sqlSugarRepository;
            dbClient = repository.Context;
            _loggerService = loggerService;
            _clientFactory = clientFactory;
        }
        /// <summary>
        /// 手机号授权,如果未注册会自动进行注册
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<ResultInfo> DecryptPhoneAsync(BusinessDecryptSubmitModel model)
        {
            var sessionBag = await SessionContainer.GetSessionAsync(model.sessionId);
            if (sessionBag == null)
            {
                return new ResultInfo(ResultState.FAIL, "sessionId未找到");
            }
            var phone = EncryptHelper.DecryptPhoneNumber(model.sessionId, model.encryptedData, model.iv);
            _loggerService.AddLogger($"手机号解密信息:{phone.ToJson()}");
            return await InsertOrUpdateAccountInfoAsync(new BusinessRegDto
            {
                isvrcode = false,
                sessionId = model.sessionId,
                NickName = phone.purePhoneNumber,
                Password = phone.purePhoneNumber,
                RePassword = phone.purePhoneNumber,
                Phone = phone.purePhoneNumber,
                code = ""
            });
        }

        /// <summary>
        /// 小程序登录
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<ResultInfo> OnLoginAsync(WXOpenLoginSubmitModel model)
        {
            #region 获取当前可用的appid
            if (!string.IsNullOrEmpty(model.appid))
            {
                var itemlist = Config.SenparcWeixinSetting.Items;
                foreach (var item in itemlist)
                {
                    if (item.Value.WxOpenAppId == model.appid)
                    {
                        WxOpenAppId = item.Value.WxOpenAppId;
                        WxOpenAppSecret = item.Value.WxOpenAppSecret;
                        break;
                    }
                }
            }
            #endregion
            var jsonResult = await SnsApi.JsCode2JsonAsync(WxOpenAppId, WxOpenAppSecret, model.code);
            if (jsonResult.errcode == ReturnCode.请求成功)
            {
                //检查此openid是否已注册
                var wxdata = await dbClient.Queryable<YB_BusinessWX>().FirstAsync(x => x.OpenId == jsonResult.openid);
                TimeSpan val = new TimeSpan(1, 0, 0);//一个小时
                if (wxdata == null)
                {
                    //记录信息
                    var sessionBag = await SessionContainer.UpdateSessionAsync(jsonResult.openid, jsonResult.openid, jsonResult.session_key, jsonResult.unionid, val);
                    return new ResultInfo(ResultState.WXUNAUTHORITY, "此账户还未注册", new WxOpenLoginData
                    {
                        sessionid = sessionBag.Key
                    });
                }
                //刷新key
                var sessionbag = await SessionContainer.UpdateSessionAsync(jsonResult.openid, jsonResult.openid, jsonResult.session_key, jsonResult.unionid, val);
                //生成token
                return await GenTokenAsync(wxdata.UserId, wxdata.BusinessId, wxdata.OpenId, sessionbag.Key);
            }
            return new ResultInfo(ResultState.FAIL, jsonResult.errmsg);
        }
        /// <summary>
        /// 根据手机号进行注册
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<ResultInfo> RegisterAsync(BusinessRegDto model)
        {
            //检查此手机号是否已注册
            if (await dbClient.Queryable<YB_Business>().AnyAsync(x => x.Phone == model.Phone))
            {
                return new ResultInfo(ResultState.FAIL, "此手机号已注册,可直接登录");
            }
            if (model.isvrcode)
            {
                if (string.IsNullOrEmpty(model.code))
                {
                    return new ResultInfo(ResultState.FAIL, "验证码不可为空");
                }
                //检查验证码
                var yzm = RedisHelpers.stringGet<string>($"ybdeviceclient_yam_{model.Phone}");
                if (model.code != yzm)
                {
                    return new ResultInfo() { code = ResultState.FAIL, message = "验证码错误" };
                }
            }
            //检查两次密码是否一致
            if (model.Password != model.RePassword)
            {
                return new ResultInfo(ResultState.FAIL, "两次密码不一致");
            }
            return await InsertOrUpdateAccountInfoAsync(model);
        }

        /// <summary>
        /// 生成code
        /// </summary>
        /// <param name="cnt"></param>
        /// <returns></returns>
        private string GenCode(int cnt) =>
            cnt switch
            {
                < 9 => $"000{cnt + 1}",
                < 99 and >= 9 => $"00{cnt + 1}",
                < 999 and >= 99 => $"0{cnt + 1}",
                < 9999 and >= 999 => $"{cnt + 1}",
                _ => ""
            };
        /// <summary>
        /// 生成token
        /// </summary>
        /// <returns></returns>
        private async Task<ResultInfo> GenTokenAsync(int userid, int businessid, string openid, string sessionid)
        {
            openid = openid.ToStr();
            sessionid = sessionid.ToStr();
            var business = await dbClient.Queryable<YB_Account>().FirstAsync(x => x.BusinessId == businessid);
            //生成token
            var token = JWTEncryption.Encrypt(new Dictionary<string, object>() {
                    {"UserId",userid},
                    {"BusinessId",businessid},
                    {"loginttime",DateTime.Now },
                    {"fansid",openid },
                    {"AccountType",business !=null?business.AccountType:1 }
                });
            var refreshToken = JWTEncryption.GenerateRefreshToken(token, 43200);
            return new ResultInfo(ResultState.SUCCESS, "登录成功", new
            {
                token = token,
                sessionid = sessionid,
                refreshtoken = refreshToken
            });
        }
        /// <summary>
        /// 添加或者更新商户信息
        /// </summary>
        /// <param name="businessRegDto"></param>
        /// <returns></returns>
        public async Task<ResultInfo> InsertOrUpdateAccountInfoAsync(BusinessRegDto businessRegDto)
        {
            SessionBag sessionBag = null;
            if (!businessRegDto.sessionId.IsEmpty())
            {
                sessionBag = await SessionContainer.GetSessionAsync(businessRegDto.sessionId);
                if (sessionBag == null)
                {
                    return new ResultInfo(ResultState.FAIL, "sessionId未找到");
                }
            }
            var busienss = await dbClient.Queryable<YB_Business>().FirstAsync(x => x.Phone == businessRegDto.Phone);
            //如果未注册自动进行注册
            if (busienss == null)
            {
                //生成编码
                int cnt = await dbClient.Queryable<YB_Business>().CountAsync(x => x.ParentId == 0);
                string scode = GenCode(cnt);
                if (string.IsNullOrEmpty(scode))
                {
                    return new ResultInfo(ResultState.FAIL, "超过最大注册数量");
                }
                var buss = new YB_Business
                {
                    CreateTime = DateTime.Now,
                    Status = (int)StatusType.Enabled,
                    Name = businessRegDto.NickName,
                    Phone = businessRegDto.Phone,
                    Remark = "",
                    ParentId = 0,
                    Type = 2, //1-系统默认,2-通过商户小程序自主注册的
                    Code = scode
                };
                var bid = await dbClient.Insertable(buss).ExecuteReturnIdentityAsync();
                var secretkey = Md5.md5(Common.CreateNo(), 16).ToLower();
                var password = Md5.md5(DESEncrypt.Encrypt(Md5.md5(businessRegDto.Password, 32).ToLower(), secretkey).ToLower(), 32).ToLower();
                var user = new YB_Account
                {
                    Secret = secretkey,
                    AccountType = (int)AccountType.agent,
                    Status = (int)StatusType.Enabled,
                    BusinessId = bid,
                    CreateTime = DateTime.Now,
                    LastVisitIP = "",
                    LastVisitTime = DateTime.Now,
                    Phone = businessRegDto.Phone,
                    RealName = businessRegDto.NickName,
                    RoleId = 2,
                    UserName = businessRegDto.Phone,
                    Password = password
                };
                int userid = await dbClient.Insertable(user).ExecuteReturnIdentityAsync();

                //插入商户数据
                await dbClient.Insertable(new YB_BusinessRealData
                {
                    BusinessCount = 0,
                    CreateTime = DateTime.Now,
                    Balance = 0,
                    BusinessId = bid,
                    DevCount = 0,
                    TodayIncome = 0,
                    TodayResultCnt = 0,
                    TotalIncome = 0,
                    TotalResultCnt = 0,
                    TotalTxAmount = 0,
                    TodayRealCnt = 0,
                    TotalRealCnt = 0,
                    TodayDevCount = 0
                }).ExecuteCommandAsync();

                //更新汇总表
                int devcnt = await dbClient.Queryable<YB_Device>().CountAsync();
                int businesscnt = await dbClient.Queryable<YB_Business>().CountAsync();
                int todaydevactinvecnt = await dbClient.Queryable<YB_Device>().Where(x => SqlFunc.DateIsSame(x.LastHeartTime, DateTime.Now)).CountAsync();
                if (await dbClient.Queryable<YB_Combined>().AnyAsync(x => x.Id == 1))
                {
                    await dbClient.Updateable<YB_Combined>().SetColumns(x => new YB_Combined
                    {
                        TotalDevCnt = devcnt,
                        BusinessCnt = businesscnt,
                        TodayDevCnt = todaydevactinvecnt
                    }).Where(x => x.Id == 1).ExecuteCommandAsync();
                }
                else
                {
                    await dbClient.Insertable(new YB_Combined
                    {
                        TodayDevCnt = todaydevactinvecnt,
                        BusinessCnt = businesscnt,
                        TodayIncome = 0,
                        TodayRegCnt = 0,
                        TodayResultCnt = 0,
                        TotalDevCnt = devcnt,
                        TotalIncome = 0,
                        TotalRegCnt = 0,
                        TotalResultCnt = 0,
                        Id = 1
                    }).ExecuteCommandAsync();
                }

                //增加关联记录
                if (sessionBag != null)
                {
                    await dbClient.Insertable(new YB_BusinessWX
                    {
                        BusinessId = bid,
                        CreateTime = DateTime.Now,
                        OpenId = sessionBag.OpenId,
                        UnionId = sessionBag.UnionId.ToStr(),
                        UserId = userid
                    }).ExecuteCommandAsync();
                }
                //生成token
                return await GenTokenAsync(userid, user.BusinessId, sessionBag?.OpenId, businessRegDto.sessionId);
            }
            else
            {
                var user = await dbClient.Queryable<YB_Account>().FirstAsync(x => x.BusinessId == busienss.Id);
                //更新数据
                if (sessionBag != null && !await dbClient.Queryable<YB_BusinessWX>().AnyAsync(x => x.BusinessId == busienss.Id && x.OpenId == sessionBag.OpenId))
                {
                    await dbClient.Insertable(new YB_BusinessWX
                    {
                        BusinessId = busienss.Id,
                        CreateTime = DateTime.Now,
                        OpenId = sessionBag.OpenId,
                        UnionId = sessionBag.UnionId.ToStr(),
                        UserId = user.Id
                    }).ExecuteCommandAsync();
                }
                //更新登录时间
                await dbClient.Updateable<YB_Account>().SetColumns(x => new YB_Account
                {
                    LastVisitIP = Net.Ip,
                    LastVisitTime = DateTime.Now
                }).Where(x => x.Id == user.Id).ExecuteCommandAsync();
                //生成token
                return await GenTokenAsync (user.Id, user.BusinessId, sessionBag?.OpenId, businessRegDto.sessionId);
            }
        }
        /// <summary>
        /// 根据手机号和密码进行登录
        /// </summary>
        /// <param name="businessLoginDto"></param>
        /// <returns></returns>
        public async Task<ResultInfo> LoginAsync(BusinessLoginDto businessLoginDto)
        {
            //检查此手机号是否已注册
            if (!await dbClient.Queryable<YB_Business>().AnyAsync(x => x.Phone == businessLoginDto.Phone))
            {
                return new ResultInfo(ResultState.FAIL, "此手机号还未注册账户");
            }
            var user = await dbClient.Queryable<YB_Account>().FirstAsync(x => x.Phone == businessLoginDto.Phone);
            if (user == null)
            {
                return new ResultInfo(ResultState.FAIL, "此手机号还未注册账户");
            }
            //检查密码是否正确
            var checkpassword = Md5.md5(DESEncrypt.Encrypt(Md5.md5(businessLoginDto.Password, 32).ToLower(), user.Secret).ToLower(), 32).ToLower();
            if (checkpassword != user.Password)
            {
                return new ResultInfo(ResultState.FAIL, "密码不正确");
            }
            return await InsertOrUpdateAccountInfoAsync(new BusinessRegDto
            {
                code = "",
                sessionId = businessLoginDto.sessionId,
                isvrcode = false,
                NickName = businessLoginDto.Phone,
                Phone = businessLoginDto.Phone,
                Password = businessLoginDto.Password,
                RePassword = businessLoginDto.Password
            });
        }
        /// <summary>
        /// 手机号快捷登录
        /// </summary>
        /// <param name="businessQLoginDto"></param>
        /// <returns></returns>
        public async Task<ResultInfo> SLoginAsync(BusinessQLoginDto businessQLoginDto)
        {
            if (businessQLoginDto.isvrcode)
            {
                if (string.IsNullOrEmpty(businessQLoginDto.code))
                {
                    return new ResultInfo(ResultState.FAIL, "验证码不可为空");
                }
                //检查验证码
                var yzm = RedisHelpers.stringGet<string>($"ybdeviceclient_yam_{businessQLoginDto.Phone}");
                if (businessQLoginDto.code != yzm)
                {
                    return new ResultInfo() { code = ResultState.FAIL, message = "验证码错误" };
                }
            }
            return await InsertOrUpdateAccountInfoAsync(new BusinessRegDto
            {
                code = "",
                sessionId = businessQLoginDto.sessionId,
                isvrcode = false,
                NickName = businessQLoginDto.Phone,
                Password = businessQLoginDto.Phone,
                Phone = businessQLoginDto.Phone,
                RePassword = businessQLoginDto.Phone
            });

        }
        /// <summary>
        /// 发送短信验证码
        /// </summary>
        /// <param name="phone"></param>
        /// <returns></returns>
        public async Task<ResultInfo> SendCodeAsync(string phone)
        {
            if (string.IsNullOrEmpty(phone))
            {
                return new ResultInfo(ResultState.FAIL, "手机号不可为空");
            }
            if (!Validate.IsValidMobile(phone))
            {
                return new ResultInfo(ResultState.FAIL, "手机号码不合法");
            }
            Random rd = new Random();
            var yzm = rd.Next(100000, 999999);
            var platform = "每日一称";
            var content = $"【{platform}】您好，欢迎使用{platform},您的手机验证码是:{yzm}，验证码一分钟内有效,若非本人操作，请忽略！";
            var data = new
            {
                phone = phone,
                Content = HttpUtility.UrlEncode(content)
            };
            var par = $"ybdeviceclient_yam_{phone}";
            if (!string.IsNullOrEmpty(RedisHelpers.stringGet<string>(par)))
            {
                return new ResultInfo(ResultState.FAIL, "请求频繁");
            }
            var url = "http://sms.ybhdmob.com/Message/Send?token=ybhdmob";
            var request = new HttpRequestMessage(HttpMethod.Post,
                   url);
            string body = data.ToJson();
            request.Content = new StringContent(body, Encoding.UTF8, "application/json");
            var client = _clientFactory.CreateClient();
            var response = await client.SendAsync(request);

            if (response.IsSuccessStatusCode)
            {
                var result = await response.Content.ReadAsStringAsync();
                var results = result.ToObject<SMSMODEL>();
                //记录日志
                var msg = $"短信发送:参数:{data.ToJson()}\r\n返回值:{result}";
                _loggerService.AddLogger(msg);
                if (results != null && results.code == 0)
                {
                    RedisHelpers.Insert(par, yzm.ToString(), 60);
                }
                return new ResultInfo(ResultState.SUCCESS, "验证码已发送");
            }
            else
            {
                return new ResultInfo(ResultState.FAIL, "短信发送失败");
            }
        }
    }
}
