using Bogus.DataSets;

using CloudGaming.Code.Account.Contract;
using CloudGaming.Code.Account.Login;
using CloudGaming.Code.Account.UserCurrency;
using CloudGaming.Code.AppExtend;
using CloudGaming.Code.DataAccess;
using CloudGaming.Code.Other;
using CloudGaming.DtoModel.Account.Login;
using CloudGaming.DtoModel.Account.User;
using CloudGaming.DtoModel.Account.User.Cache;
using CloudGaming.DtoModel.Messages;

using HuanMeng.DotNetCore.Redis;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;

using StackExchange.Redis;

using Swashbuckle.AspNetCore.SwaggerGen;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CloudGaming.Code.Account
{
    public static class AccountExtend
    {

        /// <summary>
        /// 返回对应的登录方式
        /// </summary>
        /// <param name="jsonString"></param>
        /// <returns></returns>
        public static IUserAccount? GetUserAccount(string jsonString, CloudGamingBase cloudGamingBase)
        {
            var jwt = cloudGamingBase.HttpContextAccessor.HttpContext.Request.Headers.GetAuthorization();
            if (!string.IsNullOrEmpty(jwt))
            {
                IUserAccount authorizationUserLogin = new AuthorizationUserLogin(jwt, cloudGamingBase);
                return authorizationUserLogin;
            }
            if (!string.IsNullOrEmpty(jsonString))
            {
                JObject jsonObject = JObject.Parse(jsonString);
                if (AllKeysExistIgnoreCase(jsonObject, "PhoneNumber", "VerificationCode"))
                {
                    var loginParams = JsonConvert.DeserializeObject<PhoneLoginParams>(jsonString);
                    PhoneUserLogin phoneUserLogin = new PhoneUserLogin(loginParams, cloudGamingBase);
                    return phoneUserLogin;
                }  //检测是否还有jwt登录
            }


            return null;
        }
        static bool AllKeysExistIgnoreCase(JObject jsonObject, params string[] keysToCheck)
        {
            var propertie = jsonObject.Properties();
            return keysToCheck.All(key => propertie.Any(p => string.Equals(p.Name, key, StringComparison.OrdinalIgnoreCase)));
        }

        /// <summary>
        /// 获取用户货币
        /// </summary>
        /// <param name="curreny"></param>
        /// <param name="userCurrencyType"></param>
        /// <returns></returns>
        public static decimal GetUserCurrency(this Dictionary<UserCurrencyType, T_User_Currency> curreny, UserCurrencyType userCurrencyType)
        {
            if (curreny != null)
            {
                if (curreny.TryGetValue(userCurrencyType, out var _currency))
                {
                    return _currency.CurrencyMoney;
                }
            }
            return 0;
        }

        /// <summary>
        /// 
        /// </summary>
        public static string UserInfoRedisKeyPrefix { get => "user:userInfo"; }

        /// <summary>
        /// 用户缓存的key
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public static string GetUserInfoRedisKey(int userId)
        {
            return $"{UserInfoRedisKeyPrefix}:{userId}";
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="userInfoCache"></param>
        /// <param name="userId"></param>
        /// <param name="cloudGamingBase"></param>
        /// <returns></returns>
        public static async Task<UserInfoCache?> GetUserInfo(this UserInfoCache userInfoCache, int userId, CloudGamingBase cloudGamingBase)
        {
            userInfoCache = await GetUserInfo(userId, cloudGamingBase) ?? new UserInfoCache();
            return userInfoCache;
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="cloudGamingBase"></param>
        /// <returns></returns>
        public static async Task<UserInfoCache?> GetUserInfoOrNull(int userId, CloudGamingBase cloudGamingBase)
        {
            if (userId == 0)
            {
                return new UserInfoCache();
            }
            string key = GetUserInfoRedisKey(userId);
            var userInfo = await cloudGamingBase.RedisCache.StringGetAsync<UserInfoCache>(key);
            return userInfo;
        }

        /// <summary>
        /// 删除用户缓存
        /// </summary>
        /// <param name="cloudGamingBase"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public static async Task<bool> DeleteUserInfoCache(this UserInfoCache userInfoCache, CloudGamingBase cloudGamingBase)
        {
            if (userInfoCache == null)
            {
                return true;
            }

            string key = GetUserInfoRedisKey(userInfoCache.UserId);
            return await cloudGamingBase.RedisCache.KeyDeleteAsync(key);

        }

        /// <summary>
        /// 刷新用户钻石，和是否支付缓存
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="database"></param>
        /// <param name="diamond"></param>
        /// <param name="isPay"></param>
        /// <returns></returns>
        public static async Task RefreshUserInfo(int userId, IDatabase database, int diamond, bool isPay)
        {
            string key = GetUserInfoRedisKey(userId);
            var userInfo = await database.StringGetAsync<UserInfoCache>(key);
            if (userInfo != null)
            {
                userInfo.Diamond = diamond;
                userInfo.IsPay = isPay;
                await database.StringSetAsync(key, userInfo, TimeSpan.FromMinutes(30));
            }
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="cloudGamingBase"></param>
        /// <returns></returns>
        public static async Task<UserInfoCache?> GetUserInfo(int userId, CloudGamingBase cloudGamingBase)
        {
            if (userId == 0)
            {
                return new UserInfoCache();
            }
            string key = GetUserInfoRedisKey(userId);
            var userInfo = await cloudGamingBase.RedisCache.StringGetAsync<UserInfoCache>(key);
            if (userInfo == null)
            {
                var Dao = cloudGamingBase.Dao;
                userInfo = new UserInfoCache() { };
                //用户信息
                var user = await Dao.DaoUser.Context.T_User.FirstOrDefaultAsync(it => it.Id == userId);
                //用户扩展信息
                var userData = await Dao.DaoUser.Context.T_User_Data.FirstOrDefaultAsync(it => it.UserId == userId);
                //用户货币
                var userCurrency = await Dao.DaoUser.Context.T_User_Currency.Where(it => it.UserId == userId).ToDictionaryAsync(it => (UserCurrencyType)it.CurrencyType);
                if (user == null)
                {
                    throw MessageBox.Show(ResponseCode.NotFoundRecord, "未找到用户信息");
                }
                if (userData == null)
                {
                    throw MessageBox.Show(ResponseCode.NotFoundRecord, "未找到用户扩展信息");
                }
                userInfo.LoadUserInfo(user, userData, userCurrency);
                var userPlayGameTime = await Dao.DaoPhone.Context.T_User_PlayGameTime.Where(it => it.UserId == userId).SumAsync(it => (int?)it.PlayTime);
                userInfo.UserPlayGameTime = userPlayGameTime ?? 0;
                await cloudGamingBase.RedisCache.StringSetAsync(key, userInfo, TimeSpan.FromHours(1));
            }

            return userInfo;
        }

        /// <summary>
        /// 设置用户信息
        /// </summary>
        /// <param name="database"></param>
        /// <param name="user"></param>
        /// <param name="userData"></param>
        /// <param name="userCurrency"></param>
        /// <returns></returns>
        public static async Task<UserInfoCache?> LogUserInfoCahceAsync(IDatabase database, T_User user, T_User_Data? userData = null, Dictionary<UserCurrencyType, T_User_Currency> userCurrency = null, int userPlayGameTime = 0)
        {
            var key = GetUserInfoRedisKey(user.Id);
            var userInfo = new UserInfoCache() { };
            LoadUserInfo(userInfo, user, userData, userCurrency);
            if (userPlayGameTime != 0)
            {
                //var userPlayGameTime = await Dao.DaoPhone.Context.T_User_PlayGameTime.Where(it => it.UserId == userId).SumAsync(it => (int?)it.PlayTime);
                userInfo.UserPlayGameTime = userPlayGameTime;// userPlayGameTime ?? 0;
            }
            await database.StringSetAsync(key, userInfo, TimeSpan.FromHours(1));
            return userInfo;
        }

        /// <summary>
        /// 加载用户缓存
        /// </summary>
        /// <param name="userInfo"></param>
        /// <param name="user"></param>
        /// <param name="userData"></param>
        /// <param name="userCurrency"></param>
        /// <returns></returns>
        public static UserInfoCache LoadUserInfo(this UserInfoCache userInfo, T_User? user = null, T_User_Data? userData = null, Dictionary<UserCurrencyType, T_User_Currency> userCurrency = null)
        {
            if (userInfo == null)
            {
                userInfo = new UserInfoCache();
            }
            if (user != null)
            {
                userInfo.NickName = user.NickName;
                userInfo.UserId = user.Id;
                userInfo.UserIcon = user.UserIconUrl;
                userInfo.IsRealName = user.UserRealNameStatus > 0;
                userInfo.IsJuveniles = user.UserRealNameStatus == 2;
                userInfo.UserName = user.UserName ?? "";
                userInfo.IdCard = user.IDCard ?? "";
                userInfo.IsTest = user.IsTest ?? false;

            }
            if (userData != null)
            {
                userInfo.PhoneNum = userData?.PhoneNum ?? "";
                userInfo.Email = userData?.Email ?? "";
                userInfo.DeviceNumber = userData?.DeviceNumber ?? "";
                userInfo.IsPay = userData?.IsPay ?? false;
            }
            userInfo.TotalGamingTime = 0;
            if (userCurrency != null)
            {
                userInfo.Diamond = (int)userCurrency.GetUserCurrency(UserCurrencyType.钻石);
            }
            return userInfo;
        }

        /// <summary>
        /// 加载用户缓存
        /// </summary>
        /// <param name="userInfo"></param>
        /// <param name="user"></param>
        /// <param name="userData"></param>
        /// <param name="userCurrency"></param>
        /// <returns></returns>
        public static UserInfoCache LoadUserInfo(T_User? user = null, T_User_Data? userData = null, Dictionary<UserCurrencyType, T_User_Currency> userCurrency = null)
        {
            var userInfo = new UserInfoCache();
            return LoadUserInfo(userInfo, user, userData, userCurrency);
        }


        /// <summary>
        /// 保存用户缓存
        /// </summary>
        /// <param name="cloudGamingBase"></param>
        /// <returns></returns>
        public static async Task<UserInfoCache> SaveUserInfoCacheChangesAsync(this CloudGamingBase cloudGamingBase)
        {
            var userInfo = cloudGamingBase.UserInfo;
            var key = GetUserInfoRedisKey(cloudGamingBase.UserInfo.UserId);
            await cloudGamingBase.RedisCache.StringSetAsync(key, userInfo, TimeSpan.FromHours(1));
            return userInfo;
        }

        /// <summary>
        /// 保存用户缓存
        /// </summary>
        /// <param name="cloudGamingBase"></param>
        /// <returns></returns>
        public static async Task<UserInfoCache> SaveUserInfoCacheChangesAsync(UserInfoCache userInfo, IDatabase database)
        {
            var key = GetUserInfoRedisKey(userInfo.UserId);
            await database.StringSetAsync(key, userInfo, TimeSpan.FromHours(1));
            return userInfo;
        }



        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="cloudGamingBase"></param>
        /// <param name="title"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public static async Task<bool> SendUserMessageAsync(this CloudGamingBase cloudGamingBase, string title, string content)
        {
            if (cloudGamingBase._UserId == 0)
            {
                return false;

            }
            T_User_Messages t_User_Messages = new T_User_Messages()
            {
                Content = content,
                CreateAt = DateTime.Now,
                MessageType = MessageType.user.ToString(),
                IsRead = false,
                SendAt = DateTime.Now,
                SystemId = 0,
                Title = title,
                UserId = cloudGamingBase._UserId
            };
            await cloudGamingBase.Dao.DaoPhone.Context.T_User_Messages.AddAsync(t_User_Messages);
            await cloudGamingBase.Dao.DaoPhone.Context.SaveChangesAsync();
            return true;
        }



        /// <summary>
        /// 获取用户购买过的产品
        /// </summary>
        /// <param name="userInfoCache"></param>
        /// <param name="dao"></param>
        /// <param name="database"></param>
        /// <returns></returns>
        public static async Task<Dictionary<string, int>> GetBuyProductCount(this UserInfoCache userInfoCache, DAO dao, IDatabase database)
        {
            int userId = userInfoCache.UserId;
            if (userInfoCache.BuyProductCount == null)
            {
                var orderDictionary = await dao.DaoUser.Context.T_User_Order
     .Where(it => it.UserId == userId).GroupBy(it => it.ProductId).ToDictionaryAsync(it => it.Key, it => it.Count());
                if (orderDictionary == null)
                {
                    orderDictionary = new Dictionary<string, int>();
                }
                userInfoCache.BuyProductCount = orderDictionary;
                await SaveUserInfoCacheChangesAsync(userInfoCache, database);
                //new CloudGamingBase().SaveUserInfoCacheChangesAsync();
            }
            return userInfoCache.BuyProductCount;
        }


        /// <summary>
        /// 获取用户七天签到
        /// </summary>
        /// <param name="userInfoCache"></param>
        /// <param name="dao"></param>
        /// <param name="database"></param>
        /// <returns></returns>
        public static async Task<UserSevenDayCache> GetUserSevenDay(this UserInfoCache userInfoCache, DAO dao, IDatabase database)
        {

            if (userInfoCache.UserSevenDay == null)
            {
                UserSevenDayCache userSevenDayCache = new UserSevenDayCache();

                //取出用户最后一条签到记录 
                var log = await dao.DaoPhone.Context.T_User_SignDays.Where(it => it.UserId == userInfoCache.UserId).OrderByDescending(it => it.Id).FirstOrDefaultAsync();
                if (log != null)
                {

                    if (log.SignDayTime.Date == DateTime.Now.Date)
                    {
                        userSevenDayCache.IsSignSevenDay = true;
                        //如果今天已经签到了
                        userSevenDayCache.ConsecutiveSignDays = log.SignDayNum;
                    }
                    else if (log.SignDayTime.Date == DateTime.Now.AddDays(-1).Date)
                    {
                        //判断用户昨天有没有签到过
                        userSevenDayCache.ConsecutiveSignDays = log.SignDayNum;
                        //如果用户昨天签到累计7天了，今天还没有签到，则将重置签到天数
                        if (log.SignDayNum == 7)
                        {
                            userSevenDayCache.ConsecutiveSignDays = 0;
                        }
                    }
                    else
                    {
                        //用户签到中断，重置签到天数
                        userSevenDayCache.ConsecutiveSignDays = 0;
                    }
                    userSevenDayCache.LastSevenDayTime = log.SignDayTime;
                }
                else
                {
                    userSevenDayCache.ConsecutiveSignDays = 0;
                    userSevenDayCache.IsSignSevenDay = false;

                }
                userInfoCache.UserSevenDay = userSevenDayCache;
                await SaveUserInfoCacheChangesAsync(userInfoCache, database);
            }
            return userInfoCache.UserSevenDay;

        }

        /// <summary>
        /// 获取游戏收藏记录
        /// </summary>
        /// <param name="userInfoCache"></param>
        /// <param name="dao"></param>
        /// <param name="database"></param>
        /// <returns></returns>

        public static async Task<List<string>> GetUserGameCollect(this UserInfoCache userInfoCache, DAO dao, IDatabase database)
        {
            if (userInfoCache.GameCollects == null)
            {
                userInfoCache.GameCollects = new List<string>();
                var favorite = await dao.DaoUser.Context.T_User_GameFavorite.Where(it => it.UserId == userInfoCache.UserId).OrderByDescending(it => it.FavoriteTime).Select(it => it.GameId).ToListAsync();
                userInfoCache.GameCollects.AddRange(favorite ?? new List<string>());
                await SaveUserInfoCacheChangesAsync(userInfoCache, database);
            }
            return userInfoCache.GameCollects;
        }
    }
}
