from enum import Enum


class ElementType(str, Enum):
    """
    Enum representing the type of an element.
    """

    NONE = "NONE"
    CRYO = "CRYO"
    HYDRO = "HYDRO"
    PYRO = "PYRO"
    ELECTRO = "ELECTRO"
    GEO = "GEO"
    DENDRO = "DENDRO"
    ANEMO = "ANEMO"

    def __str__(self):
        return self.value

    def __repr__(self):
        return self.value


ELEMENT_DEFAULT_ORDER = [
    ElementType.CRYO,
    ElementType.HYDRO,
    ElementType.PYRO,
    ElementType.ELECTRO,
    ElementType.GEO,
    ElementType.DENDRO,
    ElementType.ANEMO,
]


class DieColor(str, Enum):
    """
    Enum representing the color of a die. It can also be called as elemental
    type, elemental attributes. Besides existing element types, there are
    also Onmi, which can be used as any color.

    Attributes:
        CRYO (str): The die color is cryo.
        HYDRO (str): The die color is hydro.
        PYRO (str): The die color is pyro.
        ELECTRO (str): The die color is electro.
        GEO (str): The die color is geo.
        DENDRO (str): The die color is dendro.
        ANEMO (str): The die color is anemo.
        OMNI (str): The die color is omni.
    """

    CRYO = "CRYO"
    HYDRO = "HYDRO"
    PYRO = "PYRO"
    ELECTRO = "ELECTRO"
    GEO = "GEO"
    DENDRO = "DENDRO"
    ANEMO = "ANEMO"
    OMNI = "OMNI"

    def __str__(self):
        return self.value

    def __repr__(self):
        return self.value


ELEMENT_TO_DIE_COLOR = {
    ElementType.CRYO: DieColor.CRYO,
    ElementType.HYDRO: DieColor.HYDRO,
    ElementType.PYRO: DieColor.PYRO,
    ElementType.ELECTRO: DieColor.ELECTRO,
    ElementType.GEO: DieColor.GEO,
    ElementType.DENDRO: DieColor.DENDRO,
    ElementType.ANEMO: DieColor.ANEMO,
}
DIE_COLOR_TO_ELEMENT = {
    DieColor.CRYO: ElementType.CRYO,
    DieColor.HYDRO: ElementType.HYDRO,
    DieColor.PYRO: ElementType.PYRO,
    DieColor.ELECTRO: ElementType.ELECTRO,
    DieColor.GEO: ElementType.GEO,
    DieColor.DENDRO: ElementType.DENDRO,
    DieColor.ANEMO: ElementType.ANEMO,
}


class DamageElementalType(str, Enum):
    """
    Enum representing the type of a damage.
    """

    # elemental damage
    CRYO = "CRYO"
    HYDRO = "HYDRO"
    PYRO = "PYRO"
    ELECTRO = "ELECTRO"
    GEO = "GEO"
    DENDRO = "DENDRO"
    ANEMO = "ANEMO"

    # other damage
    PHYSICAL = "PHYSICAL"
    PIERCING = "PIERCING"
    HEAL = "HEAL"

    def __str__(self):
        return self.value

    def __repr__(self):
        return self.value


ELEMENT_TO_DAMAGE_TYPE = {
    ElementType.NONE: DamageElementalType.PHYSICAL,
    ElementType.CRYO: DamageElementalType.CRYO,
    ElementType.HYDRO: DamageElementalType.HYDRO,
    ElementType.PYRO: DamageElementalType.PYRO,
    ElementType.ELECTRO: DamageElementalType.ELECTRO,
    ElementType.GEO: DamageElementalType.GEO,
    ElementType.DENDRO: DamageElementalType.DENDRO,
    ElementType.ANEMO: DamageElementalType.ANEMO,
}
DAMAGE_TYPE_TO_ELEMENT = {
    DamageElementalType.CRYO: ElementType.CRYO,
    DamageElementalType.HYDRO: ElementType.HYDRO,
    DamageElementalType.PYRO: ElementType.PYRO,
    DamageElementalType.ELECTRO: ElementType.ELECTRO,
    DamageElementalType.GEO: ElementType.GEO,
    DamageElementalType.DENDRO: ElementType.DENDRO,
    DamageElementalType.ANEMO: ElementType.ANEMO,
    DamageElementalType.PHYSICAL: ElementType.NONE,
    DamageElementalType.PIERCING: ElementType.NONE,
    DamageElementalType.HEAL: ElementType.NONE,
}


class DamageType(str, Enum):
    """
    Enum representing the type of a damage.
    """

    DAMAGE = "DAMAGE"
    HEAL = "HEAL"
    ELEMENT_APPLICATION = "ELEMENT_APPLICATION"

    def __str__(self):
        return self.value

    def __repr__(self):
        return self.value


class ObjectType(str, Enum):
    """
    Enum representing the type of an object.
    """

    EMPTY = "EMPTY"
    CHARACTER = "CHARACTER"
    DICE = "DICE"
    CARD = "CARD"
    SUMMON = "SUMMON"
    SUPPORT = "SUPPORT"
    SKILL = "SKILL"
    WEAPON = "WEAPON"
    ARTIFACT = "ARTIFACT"
    TALENT = "TALENT"
    CHARACTER_STATUS = "CHARACTER_STATUS"
    TEAM_STATUS = "TEAM_STATUS"
    ARCANE = "ARCANE"
    SYSTEM = "SYSTEM"

    def __str__(self) -> str:
        return self.value

    def __repr__(self) -> str:
        return self.value


class ObjectPositionType(str, Enum):
    """
    Enum representing the position of an object.
    """

    DECK = "DECK"
    HAND = "HAND"
    SUMMON = "SUMMON"
    SUPPORT = "SUPPORT"
    DICE = "DICE"
    CHARACTER = "CHARACTER"
    CHARACTER_STATUS = "CHARACTER_STATUS"
    SKILL = "SKILL"
    TEAM_STATUS = "TEAM_STATUS"
    SYSTEM = "SYSTEM"
    INVALID = "INVALID"

    def __str__(self) -> str:
        return self.value

    def __repr__(self) -> str:
        return self.value


class FactionType(str, Enum):
    """
    Factions of characters.
    """

    MONDSTADT = "MONDSTADT"
    LIYUE = "LIYUE"
    INAZUMA = "INAZUMA"
    SUMERU = "SUMERU"
    FONTAINE = "FONTAINE"
    NATLAN = "NATLAN"
    SNEZHNAYA = "SNEZHNAYA"

    FATUI = "FATUI"
    MONSTER = "MONSTER"
    HILICHURL = "HILICHURL"

    ARKHE_PNEUMA = "ARKHE_PNEUMA"
    ARKHE_OUSIA = "ARKHE_OUSIA"

    THE_EREMITES = "THE_EREMITES"

    def __str__(self):
        return self.value

    def __repr__(self):
        return self.value


class WeaponType(str, Enum):
    """
    Types of weapons.
    """

    SWORD = "SWORD"
    CLAYMORE = "CLAYMORE"
    POLEARM = "POLEARM"
    CATALYST = "CATALYST"
    BOW = "BOW"
    OTHER = "OTHER"

    def __str__(self):
        return self.value

    def __repr__(self):
        return self.value


class SkillType(str, Enum):
    """
    Types of skills.
    """

    NORMAL_ATTACK = "NORMAL_ATTACK"
    ELEMENTAL_SKILL = "ELEMENTAL_SKILL"
    ELEMENTAL_BURST = "ELEMENTAL_BURST"
    PASSIVE = "PASSIVE"

    def __str__(self):
        return self.value

    def __repr__(self):
        return self.value


class ElementalReactionType(str, Enum):
    """
    Types of elemental reactions.
    """

    NONE = "NONE"
    MELT = "MELT"
    VAPORIZE = "VAPORIZE"
    OVERLOADED = "OVERLOADED"
    SUPERCONDUCT = "SUPERCONDUCT"
    ELECTROCHARGED = "ELECTROCHARGED"
    FROZEN = "FROZEN"
    SWIRL = "SWIRL"
    CRYSTALLIZE = "CRYSTALLIZE"
    BURNING = "BURNING"
    BLOOM = "BLOOM"
    QUICKEN = "QUICKEN"

    def __str__(self):
        return self.value

    def __repr__(self):
        return self.value


class CostLabels(int, Enum):
    SWITCH_CHARACTER = 0x1
    CARD = 0x2
    COMPANION = 0x4
    LOCATION = 0x8
    ITEM = 0x10
    ARTIFACT = 0x20
    WEAPON = 0x40
    TALENT = 0x80
    FOOD = 0x100
    ARCANE = 0x200
    NORMAL_ATTACK = 0x400
    ELEMENTAL_SKILL = 0x800
    ELEMENTAL_BURST = 0x1000
    CHARGED_ATTACK = 0x2000
    PLUNGING_ATTACK = 0x4000
    # equipment is all artifact, all weapon and some talents
    EQUIPMENT = 0x8000
    # event is some action cards, and some talents
    EVENT = 0x10000

    SKILLS = 0x1C00
    SUPPORTS = 0x1C

    def __str__(self):
        return self.name

    def __repr__(self):
        return self.name


class IconType(str, Enum):
    """
    Icon types of objects. Used for display. All summons, status, and supports
    should have one of these types.
    """

    # e.g. ???
    BUFF = "BUFF"
    # e.g. I Haven't lost yet used
    DEBUFF = "DEBUFF"
    # e.g. Changing Shifts
    SPECIAL = "SPECIAL"
    # e.g. enemy hydro abyss mage
    DAZE = "DAZE"
    # e.g. enemy dog
    DOT = "DOT"
    # Frozen
    FROZEN = "FROZEN"

    # e.g. Collei talent
    ATK_SELF = "ATK_SELF"
    # e.g. Tandoori Chicken
    ATK_UP = "ATK_UP"
    # e.g. kazuha talent
    ATK_UP_FIRE = "ELEMENT_ATK_UP_FIRE"
    ATK_UP_ELEC = "ELEMENT_ATK_UP_ELEC"
    ATK_UP_ICE = "ELEMENT_ATK_UP_ICE"
    ATK_UP_WATER = "ELEMENT_ATK_UP_WATER"
    ATK_UP_WIND = "ELEMENT_ATK_UP_WIND"
    ATK_UP_ROCK = "ELEMENT_ATK_UP_ROCK"
    ATK_UP_GRASS = "ELEMENT_ATK_UP_GRASS"
    # e.g. keqing, ayaka
    ELEMENT_ENCHANT_FIRE = "ELEMENT_ENCHANT_FIRE"
    ELEMENT_ENCHANT_ELEC = "ELEMENT_ENCHANT_ELEC"
    ELEMENT_ENCHANT_ICE = "ELEMENT_ENCHANT_ICE"
    ELEMENT_ENCHANT_WATER = "ELEMENT_ENCHANT_WATER"
    ELEMENT_ENCHANT_WIND = "ELEMENT_ENCHANT_WIND"
    ELEMENT_ENCHANT_ROCK = "ELEMENT_ENCHANT_ROCK"
    ELEMENT_ENCHANT_GRASS = "ELEMENT_ENCHANT_GRASS"
    # debuffs
    DEBUFF_ELEMENT_FIRE = "DEBUFF_ELEMENT_FIRE"
    DEBUFF_ELEMENT_ELEC = "DEBUFF_ELEMENT_ELEC"
    DEBUFF_ELEMENT_ICE = "DEBUFF_ELEMENT_ICE"
    DEBUFF_ELEMENT_WATER = "DEBUFF_ELEMENT_WATER"
    DEBUFF_ELEMENT_WIND = "DEBUFF_ELEMENT_WIND"
    DEBUFF_ELEMENT_ROCK = "DEBUFF_ELEMENT_ROCK"
    DEBUFF_ELEMENT_GRASS = "DEBUFF_ELEMENT_GRASS"
    DEBUFF_ELEMENT_PHYSICS = "DEBUFF_ELEMENT_PHYSICS"
    # e.g. Lotus Flower Crisp, Ushi
    BARRIER = "BARRIER"
    # e.g. Crystallize, Unmovable Mountain
    SHIELD = "SHIELD"
    # e.g. pizza
    HEAL = "HEAL"
    # e.g. Electro Hypostasis
    REVIVE = "REVIVE"

    # food card used for character, or egg used for team.
    FOOD = "FOOD"

    # e.g. most of summons
    TIMESTATE = "TIMESTATE"
    # e.g. Timmie, Liben
    COUNTER = "COUNTER"

    # e.g. Jade Chamber, Traveler's Handy Sword
    NONE = "NONE"

    # with others, the status has its special icon based on its name
    OTHERS = "OTHERS"

    def __str__(self):
        return self.name

    def __repr__(self):
        return self.name


ELEMENT_TO_ATK_UP_ICON = {
    ElementType.CRYO: IconType.ATK_UP_ICE,
    ElementType.HYDRO: IconType.ATK_UP_WATER,
    ElementType.PYRO: IconType.ATK_UP_FIRE,
    ElementType.ELECTRO: IconType.ATK_UP_ELEC,
    ElementType.GEO: IconType.ATK_UP_ROCK,
    ElementType.DENDRO: IconType.ATK_UP_GRASS,
    ElementType.ANEMO: IconType.ATK_UP_WIND,
}


ELEMENT_TO_ENCHANT_ICON = {
    ElementType.CRYO: IconType.ELEMENT_ENCHANT_ICE,
    ElementType.HYDRO: IconType.ELEMENT_ENCHANT_WATER,
    ElementType.PYRO: IconType.ELEMENT_ENCHANT_FIRE,
    ElementType.ELECTRO: IconType.ELEMENT_ENCHANT_ELEC,
    ElementType.GEO: IconType.ELEMENT_ENCHANT_ROCK,
    ElementType.DENDRO: IconType.ELEMENT_ENCHANT_GRASS,
    ElementType.ANEMO: IconType.ELEMENT_ENCHANT_WIND,
}


class PlayerActionLabels(int, Enum):
    SKILL = 0x1
    SWITCH = 0x2
    CARD = 0x4
    TUNE = 0x8
    END = 0x10

    def __str__(self):
        return self.name

    def __repr__(self):
        return self.name
