using AutoMapper;

using Bogus;

using CloudGaming.Code.Config;
using CloudGaming.Code.DataAccess;
using CloudGaming.DtoModel;
using CloudGaming.DtoModel.Game;
using CloudGaming.GameModel.Db.Db_Game;

using HuanMeng.DotNetCore.CacheHelper;
using HuanMeng.DotNetCore.CacheHelper.Contract;
using HuanMeng.DotNetCore.Redis;

using Newtonsoft.Json;

using Org.BouncyCastle.Utilities.Collections;

using StackExchange.Redis;

using System.Collections.Generic;
using System.Linq;

namespace CloudGaming.Code.Cache.Special
{
    /// <summary>
    /// 游戏缓存表
    /// </summary>
    public class GameEntityCache(DAO dao, IDatabase database, IMapper mapper, AppConfig appConfig) : CommonDataEntityCache<GameInfo>(GameEntityCache.GameEntityCacheLock, 60 * 60 * 24 * 7), ICacheClearLocalData
    {
        public static object GameEntityCacheLock;

        public override string key => $"{appConfig.Identifier}:game:gameInfo";

        public string locaKey => $"lock:gameInfo";
        public string RedisKey => $"cache:game:gameInfo";

        public override List<GameInfo> GetDataList()
        {
            var gameCbtList = dao.DaoPhone.Context.T_GameCBT.AsNoTracking().Where(it => it.IsOnline).ToList() ?? new List<T_GameCBT>();
            var gameListDict = dao.DaoGame.Context.T_Game_List.AsNoTracking().ToDictionary(g => g.GameId);
            var gameChildList = dao.DaoGame.Context.T_Game_ChildList.AsNoTracking().ToList();
            var gameTypesDict = dao.DaoGame.Context.T_Game_Types.AsNoTracking().ToDictionary(type => type.TypeId);
            var gameTagsDict = dao.DaoGame.Context.T_Game_Tags.AsNoTracking().ToDictionary(tag => tag.TagId);
            //游戏分享头像
            var gameUserShare = dao.DaoGame.Context.T_Game_UserShare.AsNoTracking().GroupBy(it => it.GameId).ToDictionary(it => it.Key, it => it.Last().NickName);
            //默认游戏钻石消耗
            var defaultConsumeDiamondNumHour = 0;
            var appConfig = dao.DaoExt.Context.T_App_Config.AsNoTracking().Where(it => it.ConfigType == 3).ToList();
            if (appConfig != null && appConfig.Count > 0)
            {
                var appConfigList = mapper.Map<List<AppConfigCache>>(appConfig);
                var config = appConfigList.GetAppConfig(3, 1, null);

                if (!string.IsNullOrEmpty(config?.ConfigValue))
                {
                    int.TryParse(config?.ConfigValue, out defaultConsumeDiamondNumHour);
                }
            }
            var faker = new Faker("zh_CN");
            var gameInfos = gameCbtList
                .Where(gameCbt => gameListDict.ContainsKey(gameCbt.GameId))
                .Select(gameCbt =>
                {
                    var game = gameListDict[gameCbt.GameId];
                    var gameInfo = mapper.Map<GameInfo>(gameCbt);
                    game.ToGameInfo(gameInfo);
                    gameInfo.GameType = GetGameExtendedAttributes(gameChildList, gameCbt.GameId, 1, gameTypesDict);
                    gameInfo.GameTags = GetGameExtendedAttributes(gameChildList, gameCbt.GameId, 2, gameTagsDict);
                    if (!gameUserShare.TryGetValue(gameCbt.GameId, out string NickName))
                    {
                        string chineseName = faker.Internet.UserName();
                        NickName = chineseName;
                    }
                    gameInfo.GameShare = $"{NickName}";
                    gameInfo.GameShareUserIcon = 90001;
                    if (gameInfo.ConsumeDiamondNumHour == 0)
                    {
                        gameInfo.ConsumeDiamondNumHour = defaultConsumeDiamondNumHour;
                    }
                    if (gameInfo.ConsumeDiamondNumHour > 0)
                    {
                        gameInfo.GameDetailsofCharges = $"游戏资费：游玩按分钟计费，{gameInfo.ConsumeDiamondNumHour}钻石/小时。";
                    }
                    else
                    {
                        gameInfo.GameDetailsofCharges = $"游戏免费";
                    }
                    //gameInfo.GameIntroduce
                    return gameInfo;
                })
                .ToList();

            return gameInfos;
        }

        /// <summary>
        /// 
        /// </summary>
        public override List<GameInfo> DataList
        {
            get
            {
            start:
                if (_dataList != null) return _dataList;

                var tempDataList = MemoryCacheHelper.GetCache<List<GameInfo>>(key);
                if (tempDataList != null)
                {
                    _dataList = tempDataList;
                    return _dataList;
                }

                long hashLength = database.HashLength(RedisKey);
                if (hashLength > 0)
                {
                    var hashEntries = database.HashGetAll(RedisKey);
                    var list = hashEntries
                        .Where(entry => !string.IsNullOrEmpty(entry.Value))
                        .Select(entry => JsonConvert.DeserializeObject<GameInfo>(entry.Value))
                        .ToList();

                    MemoryCacheHelper.SetCache(key, list, 60 * 60 * 12);
                    _dataList = list;
                    return _dataList;
                }

                if (!database.StringSetLock(locaKey, "1", 5))
                {
                    goto start;
                }

                tempDataList ??= GetDataList();
                var serializedGameInfos = tempDataList
                    .Select(info => new HashEntry($"gameInfo:{info.GameId}", JsonConvert.SerializeObject(info)))
                    .ToArray();
                database.HashSet(RedisKey, serializedGameInfos);
                database.StringSet($"time:{RedisKey.Replace(":", ".")}", $"刷新游戏缓存时间{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
                MemoryCacheHelper.SetCache(key, tempDataList, 60 * 60 * 12);
                _dataList = tempDataList;
                database.KeyDelete(locaKey);
                return _dataList;
            }
        }


        private Dictionary<string, GameInfo> gameInfoDic;
        /// <summary>
        /// 游戏详情
        /// </summary>
        public Dictionary<string, GameInfo> GameInfoDic
        {
            get
            {
                if (gameInfoDic == null)
                {
                    gameInfoDic = DataList.ToDictionary(it => it.GameId);
                }
                return gameInfoDic;
            }
        }

        /// <summary>
        /// 获取游戏详情
        /// </summary>
        /// <param name="gameId"></param>
        /// <returns></returns>
        public GameInfo? this[string? gameId]
        {
            get
            {
                if (string.IsNullOrEmpty(gameId))
                {
                    return null;
                }
                if (GameInfoDic.TryGetValue(gameId, out var gameInfo))
                {
                    return gameInfo;
                }
                return null;
            }
        }

        private List<GameExtendedAttribute> GetGameExtendedAttributes<T>(
            List<T_Game_ChildList> gameChildList,
            string gameId,
            int childType,
            Dictionary<int, T> dictionary) where T : class
        {
            return gameChildList
                .Where(it => it.GameId == gameId && it.ChildType == childType && (it.ChildId ?? 0) > 0)
                .OrderBy(it => it.OrderId)
                .Select(it =>
                {
                    dictionary.TryGetValue(it.ChildId.Value, out var item);
                    return item switch
                    {
                        T_Game_Types type => new GameExtendedAttribute
                        {
                            Id = type.TypeId,
                            Name = type.TypeName,
                            OrderId = it.OrderId
                        },
                        T_Game_Tags tag => new GameExtendedAttribute
                        {
                            Id = tag.TagId,
                            Name = tag.TagName,
                            OrderId = it.OrderId
                        },
                        _ => new GameExtendedAttribute()
                    };
                })
                .Where(attr => attr.Id > 0)
                .ToList();
        }

        public override bool ClearData()
        {
            database.KeyDelete(RedisKey);
            MemoryCacheHelper.DelCache(key);
            _dataList = null;
            gameInfoDic = null;
            return true;
        }

        public override void ReloadData()
        {
            database.KeyDelete(RedisKey);
            MemoryCacheHelper.DelCache(key);
            _dataList = null;
            gameInfoDic = null;
            var x = DataList;
        }

        public bool ClearLocalData()
        {
            MemoryCacheHelper.DelCache(key);
            _dataList = null;
            gameInfoDic = null;
            return true;
        }
    }
}
