import json
from loguru import logger

from Config import *
from API_TitleServer import *
from HelperGetUserThing import implGetUser_
from HelperUploadUserPlayLog import apiUploadUserPlaylog
from HelperUserAll import generateFullUserAll

def generateMusicData():
    """生成一份占位的音乐数据"""
    return {
        "musicId": 834, # PANDORA PARADOXXX
        "level": 4,
        "playCount": 1,
        "achievement": 0,
        "comboStatus": 0,
        "syncStatus": 0,
        "deluxscoreMax": 0,
        "scoreRank": 0,
        "extNum1": 0
    }

def applyUserAllPatches(userAll, patches):
    """
    递归地将给定的补丁应用到用户数据的各个层次。

    :param userAll: 原始用户数据
    :param patches: 包含所有patch的字典
    """
    for key, value in patches.items():
        if isinstance(value, dict) and key in userAll and isinstance(userAll[key], dict):
            # 如果patch的值是字典,并且userAll中对应的key也是字典,递归处理
            applyUserAllPatches(userAll[key], value)
        elif isinstance(value, list) and key in userAll and isinstance(userAll[key], list):
            # 如果值是列表,进行详细的更新处理
            for i, patch_item in enumerate(value):
                if i < len(userAll[key]) and isinstance(patch_item, dict) and isinstance(userAll[key][i], dict):
                    # 如果列表项是字典,更新字典中的字段
                    applyUserAllPatches(userAll[key][i], patch_item)
                elif i >= len(userAll[key]):
                    # 如果patch的列表比userAll的列表长,追加新的元素
                    userAll[key].append(patch_item)
        else:
            # 否则直接更新或添加key
            userAll[key] = value
            
def implFullPlayAction(userId: int, currentLoginTimestamp:int, currentLoginResult, musicData, userAllPatches, debugMode=False):
    """
    一份完整的上机实现,可以打 patch 来实现各种功能
    需要在外部先登录并传入登录结果
    """
    
    # 取得 UserData
    currentUserData = implGetUser_("Data", userId)
    currentUserData2 = currentUserData['userData']

    # 构建并上传一个游玩记录
    currentUploadUserPlaylogApiResult = apiUploadUserPlaylog(userId, musicData, currentUserData2, currentLoginResult['loginId'])
    logger.debug(f"上传 UserPlayLog 结果: {currentUploadUserPlaylogApiResult}")

    # 构建并上传 UserAll
    retries = 0
    while retries < 3:
        # 计算一个特殊数
        currentSpecialNumber = calcSpecialNumber()
        # 生成出 UserAll
        currentUserAll = generateFullUserAll(userId, currentLoginResult, currentLoginTimestamp, currentUserData2, currentSpecialNumber)
        # 应用参数里的补丁
        applyUserAllPatches(currentUserAll, userAllPatches)
        
        # 调试模式下直接输出数据
        if debugMode:
            logger.debug("调试模式:构建出的 UserAll 数据:" + json.dumps(currentUserAll, indent=4))
            logger.info("Bye!")
            return

        # 建构 Json 数据
        data = json.dumps(currentUserAll)
        # 开始上传 UserAll
        try:
            currentUserAllResult = json.loads(apiSDGB(data, "UpsertUserAllApi", userId))
        except SDGBRequestError:
            logger.warning("上传 UserAll 出现 500. 重建数据.")
            retries += 1
            continue
        except Exception:
            raise SDGBApiError("邪门错误")
        # 成功上传后退出循环
        break
    else: # 重试次数超过3次
        raise SDGBRequestError
        
    logger.info("上机:结果:"+ str(currentUserAllResult))
    return currentUserAllResult