public static IEnumerable <UserGameLevel> AddOrUpdateUserGameLevel(
            this InWordsDataContext context,
            List <LevelScore> levelScores,
            int userId)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (levelScores == null)
            {
                return(Array.Empty <UserGameLevel>());
            }

            levelScores.AddRange(GetTotalScores(levelScores));

            // select all games
            var types         = levelScores.Select(d => d.GameType).Distinct().ToArray();
            var levelIds      = levelScores.Select(d => d.GameLevelId).Distinct().ToArray();
            var existedLevels = context.UserGameLevels
                                .Where(u => u.UserId == userId)
                                .Where(u => types.Contains(u.GameType))
                                .Where(u => levelIds.Contains(u.GameLevelId));

            // find all users games
            var usersGames = from gameLevel in existedLevels
                             join usersGame in context.UserGameLevels.Where(s => s.UserId == userId)
                             on gameLevel.GameLevelId equals usersGame.GameLevelId into ug
                             from usersGame in ug.DefaultIfEmpty()
                             select new { gameLevel.GameLevelId, usersGame };

            // create if not exist
            Dictionary <(int, GameType), UserGameLevel> userGameLevels = new Dictionary <(int, GameType), UserGameLevel>();
            IList <UserGameLevel> corrupted = new List <UserGameLevel>();

            foreach (var ugame in usersGames)
            {
                if (ugame == null)
                {
                    continue;
                }

                var currentUserGame = ugame.usersGame;
                var key             = (ugame.GameLevelId, currentUserGame.GameType);
                if (userGameLevels.ContainsKey(key))
                {
                    if (userGameLevels[key].UserGameLevelId < currentUserGame.UserGameLevelId)
                    {
                        int maxScore = Math.Max(userGameLevels[key].UserStars, currentUserGame.UserStars);
                        currentUserGame.UserStars = maxScore;
                        corrupted.Add(userGameLevels[key]);
                        userGameLevels[key] = currentUserGame;
                    }
                }
                else
                {
                    userGameLevels.Add(key, currentUserGame);
                }
            }
            context.RemoveRange(corrupted);

            // update if currentScore > score in database
            foreach (var ls in levelScores)
            {
                UserGameLevel currentScore;
                var           key = (ls.GameLevelId, ls.GameType);
                if (userGameLevels.ContainsKey(key))
                {
                    currentScore = userGameLevels[key];
                }
                else
                {
                    currentScore = new UserGameLevel(userId, ls.GameLevelId, ls.Score, ls.GameType);
                    userGameLevels.Add(key, currentScore);
                    context.Add(currentScore);
                }

                if (currentScore.UserStars < ls.Score)
                {
                    currentScore.UserStars = ls.Score;
                }
            }
            return(userGameLevels.Values);
        }