import json
import math
from collections import defaultdict

def GetName(charaData):
    name = "no name"
    if charaData is not None:
        if charaData["nameEn"] != "":
            name = charaData["nameEn"]
        elif charaData["name"] != "":
            name = charaData["name"]
        if charaData["nickname"] != "":
            name += " " + charaData["nickname"]
    return name

def GetAttackBase(alphaBase, level):
    if level <= alphaBase["atkLvMiddleNum"]:
        t = (level - 1) / (alphaBase["atkLvMiddleNum"]-1)
        return lerp(alphaBase["atkParamLv1"], alphaBase["atkParamLvMiddle"], t)
    else:
        t = (level - alphaBase["atkLvMiddleNum"]) / (99 - alphaBase["atkLvMiddleNum"])
        return lerp(alphaBase["atkParamLvMiddle"], alphaBase["atkParamLv99"], t)

def GetDefenseBase(alphaBase, level):
    if level <= alphaBase["defLvMiddleNum"]:
        t = (level - 1) / (alphaBase["defLvMiddleNum"]-1)
        return lerp(alphaBase["defParamLv1"], alphaBase["defParamLvMiddle"], t)
    else:
        t = (level - alphaBase["defLvMiddleNum"]) / (99 - alphaBase["defLvMiddleNum"])
        return lerp(alphaBase["defParamLvMiddle"], alphaBase["defParamLv99"], t)

def GetHealthBase(alphaBase, level):
    if level <= alphaBase["hpLvMiddleNum"]:
        t = (level - 1) / (alphaBase["hpLvMiddleNum"]-1)
        return lerp(alphaBase["hpParamLv1"], alphaBase["hpParamLvMiddle"], t)
    else:
        t = (level - alphaBase["hpLvMiddleNum"]) / (99 - alphaBase["hpLvMiddleNum"])
        return lerp(alphaBase["hpParamLvMiddle"], alphaBase["hpParamLv99"], t)

def get_all_stats(chara, alphaBase, max_level: bool, rising_status_pattern):
    level = 99 if max_level else 1
    
    hp = GetHealthBase(alphaBase, level)
    atk = GetAttackBase(alphaBase, level)
    defe = GetDefenseBase(alphaBase, level)

    if max_level:
        starBoost = 1 + (chara["rankHigh"] - 1) * 0.02
        hp = int(math.ceil((hp + chara["promoteBonus"]["hp"]) * starBoost) + chara["costumeBonus"]["hp"])
        atk = int(math.ceil((atk + chara["promoteBonus"]["atk"]) * starBoost) + chara["costumeBonus"]["atk"])
        defe = int(math.ceil((defe + chara["promoteBonus"]["def"]) * starBoost) + chara["costumeBonus"]["def"])
        evd = 10 * alphaBase["avoidRatio"] + chara["promoteBonus"]["evd"]
        beatBonus = chara["promoteBonus"]["beat"] / 10
        actBonus = chara["promoteBonus"]["act"] / 10
        tryBonus = chara["promoteBonus"]["try"] / 10

        if rising_status_pattern is not None:
            for i in range(51):
                hp += rising_status_pattern["hp"]
                atk += rising_status_pattern["atk"]
                defe += rising_status_pattern["def"]
    else:
        starBoost = 1 + (chara["rankLow"] - 1) * 0.02
        hp = int(math.ceil(hp * starBoost))
        atk = int(math.ceil(atk * starBoost))
        defe = int(math.ceil(defe * starBoost))
        evd = 10 * alphaBase["avoidRatio"]
        beatBonus = 0
        actBonus = 0
        tryBonus = 0


    status = hp * 8 / 10
    if hp * 8 % 10 > 0:
        status += 1
    status += atk * 3 + defe * 2

    result = {
        "level" : level,
        "status" : int(status),
        "wr" : chara["rankHigh"] if max_level else chara["rankLow"],
        "hp" : hp,
        "atk" : atk,
        "def" : defe,
        "evd" : evd,
        "beat" : beatBonus,
        "act" : actBonus,
        "try" : tryBonus,
    }

    return result

def fill_miracle_numbers(chara):
    output = []
    damages = {}
    buffs = defaultdict(list)

    for i, damage_param in enumerate(chara["arts"]["damageList"]):
        damages[f"[DAMAGE{i}]"] = damage_param

    for i, buff_param in enumerate(chara["arts"]["buffList"]):
        buffs[f"[BUFF{i}]"].append(buff_param)
        buffs[f"[HEAL{i}]"].append(buff_param)
        buffs[f"[INCREMENT{i}]"].append(buff_param)

    for i in range(1, 7):
        base_text = chara["arts"]["actionEffect"]
        for damage_key, damage_value in damages.items():
            new_value = str(int(damage_value["damageRate"] * (1 + damage_value["growthRate"] * (i - 1)) * 100 + 0.01))
            base_text = base_text.replace(damage_key, new_value)
        
        for buff_key, buff_value_list in buffs.items():
            buff_value = buff_value_list[0]
            if buff_key[1] == 'B':
                new_value = str(int(abs(buff_value["coefficient"] * (1 + buff_value["growthRate"] * (i - 1)) - 1) * 100 + 0.01))
                base_text = base_text.replace(buff_key, new_value)
            elif buff_key[1] == 'H':
                new_value = str(int(buff_value["coefficient"] * (1 + buff_value["growthRate"] * (i - 1)) * 100 + 0.01))
                base_text = base_text.replace(buff_key, new_value)
            elif buff_key[1] == 'I':
                new_value = str(int(abs(buff_value["increment"]) * (1 + buff_value["growthRate"] * (i - 1)) + 0.01))
                base_text = base_text.replace(buff_key, new_value)
        
        output.append(base_text)

    return output

def toJSON(chara):
    return json.dumps(chara, default=lambda o: o.__dict__, 
        sort_keys=True, indent=1, ensure_ascii=False)

def lerp(a, b, t):
    return (1 - t) * a + t * b