from enum import Enum, IntEnum
from typing import Optional
from core.utils import floor_to_nearest_005

class ChuniConstants:
    GAME_CODE = "SDBT"
    GAME_CODE_NEW = "SDHD"
    GAME_CODE_INT = "SDGS"
    GAME_CODE_CHN = "SDHJ"

    CONFIG_NAME = "chuni.yaml"

    VER_CHUNITHM = 0
    VER_CHUNITHM_PLUS = 1
    VER_CHUNITHM_AIR = 2
    VER_CHUNITHM_AIR_PLUS = 3
    VER_CHUNITHM_STAR = 4
    VER_CHUNITHM_STAR_PLUS = 5
    VER_CHUNITHM_AMAZON = 6
    VER_CHUNITHM_AMAZON_PLUS = 7
    VER_CHUNITHM_CRYSTAL = 8
    VER_CHUNITHM_CRYSTAL_PLUS = 9
    VER_CHUNITHM_PARADISE = 10

    VER_CHUNITHM_NEW = 11
    VER_CHUNITHM_NEW_PLUS = 12
    VER_CHUNITHM_SUN = 13
    VER_CHUNITHM_SUN_PLUS = 14
    VER_CHUNITHM_LUMINOUS = 15
    VER_CHUNITHM_LUMINOUS_PLUS = 16
    VER_CHUNITHM_VERSE = 17
    VER_CHUNITHM_X_VERSE = 18

    VERSION_NAMES = [
        "CHUNITHM",
        "CHUNITHM PLUS",
        "CHUNITHM AIR",
        "CHUNITHM AIR PLUS",
        "CHUNITHM STAR",
        "CHUNITHM STAR  PLUS",
        "CHUNITHM AMAZON",
        "CHUNITHM AMAZON PLUS",
        "CHUNITHM CRYSTAL",
        "CHUNITHM CRYSTAL PLUS",
        "CHUNITHM PARADISE",
        "CHUNITHM NEW!!",
        "CHUNITHM NEW PLUS!!",
        "CHUNITHM SUN",
        "CHUNITHM SUN PLUS",
        "CHUNITHM LUMINOUS",
        "CHUNITHM LUMINOUS PLUS",
        "CHUNITHM VERSE",
        "CHUNITHM X-VERSE",
    ]

    SCORE_RANK_INTERVALS_OLD = [
        (1007500, "SSS"),
        (1000000, "SS"),
        ( 975000, "S"),
        ( 950000, "AAA"),
        ( 925000, "AA"),
        ( 900000, "A"),
        ( 800000, "BBB"),
        ( 700000, "BB"),
        ( 600000, "B"),
        ( 500000, "C"),
        (      0, "D"),
    ]

    SCORE_RANK_INTERVALS_NEW = [
        (1009000, "SSS+"),  # New only
        (1007500, "SSS"),
        (1005000, "SS+"),  # New only
        (1000000, "SS"),
        ( 990000, "S+"),  # New only
        ( 975000, "S"),
        ( 950000, "AAA"),
        ( 925000, "AA"),
        ( 900000, "A"),
        ( 800000, "BBB"),
        ( 700000, "BB"),
        ( 600000, "B"),
        ( 500000, "C"),
        (      0, "D"),
    ]

    VERSION_LUT = {
        "100": VER_CHUNITHM,
        "105": VER_CHUNITHM_PLUS,
        "110": VER_CHUNITHM_AIR,
        "115": VER_CHUNITHM_AIR_PLUS,
        "120": VER_CHUNITHM_STAR,
        "125": VER_CHUNITHM_STAR_PLUS,
        "130": VER_CHUNITHM_AMAZON,
        "135": VER_CHUNITHM_AMAZON_PLUS,
        "140": VER_CHUNITHM_CRYSTAL,
        "145": VER_CHUNITHM_CRYSTAL_PLUS,
        "150": VER_CHUNITHM_PARADISE,
        "200": VER_CHUNITHM_NEW,
        "205": VER_CHUNITHM_NEW_PLUS,
        "210": VER_CHUNITHM_SUN,
        "215": VER_CHUNITHM_SUN_PLUS,
        "220": VER_CHUNITHM_LUMINOUS,
        "225": VER_CHUNITHM_LUMINOUS_PLUS,
        "230": VER_CHUNITHM_VERSE,
        "240": VER_CHUNITHM_X_VERSE,
    }

    @classmethod
    def game_ver_to_string(cls, ver: int):
        return cls.VERSION_NAMES[ver]

    @classmethod
    def int_ver_to_game_ver(cls, ver: int) -> Optional[int]:
        """ Takes an int ver (ex 100 for 1.00) and returns an internal game version """
        return cls.VERSION_LUT.get(str(floor_to_nearest_005(ver)), None)

class MapAreaConditionType(IntEnum):
    """
    Condition IDs for the `GetGameMapAreaConditionApi` and `GetGameUCConditionApi` requests.

    - "Item" or "locked item" refers to the map area, unlock challenge or
    Linked VERSE locked using this system.
    - "Chart ID" refers to musicID \\* 100 + difficulty, where difficulty is 0 for BASIC
    up to 6 for WORLD'S END. For example, Halcyon ULTIMA is 17305.
    """

    INVALID = 0
    """
    Invalid condition type. Should cause the hidden item to be automatically unlocked,
    but seemingly only works with map areas.
    """

    MAP_CLEARED = 1
    """Finish the map with ID `conditionId`."""

    MAP_AREA_CLEARED = 2
    """Finish the map area with ID `conditionId`."""

    TROPHY_OBTAINED = 3
    """Unlock the trophy with ID `conditionId`."""

    TROPHY_EQUIPPED = 4
    """
    Equip the trophy with ID `conditionId`. The item is locked again when the trophy is
    unequipped.
    """

    NAMEPLATE_OBTAINED = 5
    """Unlock the nameplate with ID `conditionId`."""

    NAMEPLATE_EQUIPPED = 6
    """
    Equip the nameplate with ID `conditionId`. The item is locked again when the nameplate
    is unequipped.
    """

    CHARACTER_OBTAINED = 7
    """Unlock the character with ID `conditionId`."""

    CHARACTER_EQUIPPED = 8
    """
    Equip the character with ID `conditionId`. The item is locked again when the character
    is unequipped.
    """

    CHARACTER_TRANSFORM_EQUIPPED = 9
    """
    Equip the character, with the character transform ID `conditionId`. The item is locked again
    if the incorrect character is equipped, or the correct character is equipped with the wrong
    transform.
    """

    MUSIC_OBTAINED = 10
    """Unlock the music with ID `conditionId`."""

    AVATAR_ACCESSORY_OBTAINED = 11
    """Unlock the avatar accessory with ID `conditionId`."""

    AVATAR_ACCESSORY_EQUIPPED = 12
    """
    Equip the avatar accessory with ID `conditionId`. The item is locked again when the avatar
    accessory is unequipped.
    """

    MAP_ICON_OBTAINED = 13
    """Unlock the map icon with ID `conditionId`."""

    MAP_ICON_EQUIPPED = 14
    """
    Equip the map icon with ID `conditionId`. The item is locked again when the map icon is
    unequipped.
    """

    SYSTEM_VOICE_OBTAINED = 15
    """Unlock the system voice with ID `conditionId`."""

    SYSTEM_VOICE_EQUIPPED = 16
    """
    Equip the system voice with ID `conditionId`. The item is locked again when the system voice
    is unequipped.
    """

    ALL_JUSTICE_CRITICAL = 17
    """Obtain ALL JUSTICE CRITICAL on the chart given by `conditionId`."""

    RANK_SSSP = 18
    """Obtain rank SSS+ on the chart given by `conditionId`."""

    RANK_SSS = 19
    """Obtain rank SSS on the chart given by `conditionId`."""

    RANK_SSP = 20
    """Obtain rank SS+ on the chart given by `conditionId`."""

    RANK_SS = 21
    """Obtain rank SS on the chart given by `conditionId`."""

    RANK_SP = 22
    """Obtain rank S+ on the chart given by `conditionId`."""

    RANK_S = 23
    """Obtain rank S on the chart given by `conditionId`."""

    RANK_AAA = 24
    """Obtain rank AAA on the chart given by `conditionId`."""

    RANK_AA = 25
    """Obtain rank AA on the chart given by `conditionId`."""

    RANK_A = 26
    """Obtain rank A on the chart given by `conditionId`."""

    MINIMUM_BEST_30_AVERAGE = 27
    """Obtain a best 30 average of at least `conditionId / 100`."""

    ALL_JUSTICE = 28
    """Obtain ALL JUSTICE on the chart given by `conditionId`."""

    FULL_COMBO = 29
    """Obtain FULL COMBO on the chart given by `conditionId`."""

    UNLOCK_CHALLENGE_DISCOVERED = 30
    """Discover/unlock the unlock challenge with ID `conditionId`."""

    UNLOCK_CHALLENGE_CLEARED = 31
    """Clear the unlock challenge with ID `conditionId`."""

    MINIMUM_RATING = 32
    """Obtain a rating of at least `conditionId / 100`."""


class LinkedVerseUnlockConditionType(IntEnum):
    """
    `conditionList` is a semicolon-delimited list of numbers, where the number's meaning
    is defined by the specific `conditionId`. Additionally, each element of the list
    can be further separated by underscores. For example `1;2_3;4` means that the player
    must achieve 1 AND (2 OR 3) AND 4.
    """

    PLAY_SONGS = 33
    """
    Play songs given by `conditionList`, where `conditionList` is a
    list of song IDs.
    """

    COURSE_CLEAR_AND_CLASS_EMBLEM = 34
    """
    Obtain a class emblem (by clearing all courses of a given class) on **any**
    of the classes given by `conditionList`, where `conditionList` is an
    underscore-separated list of class IDs (1 for CLASS I to 6 for CLASS ∞).
    """

    TROPHY_OBTAINED = 35
    """
    Obtain trophies given by `conditionList`, where `conditionList` is a
    list of trophy IDs.
    """

    PLAY_SONGS_IN_FAVORITE = 36
    """
    Play songs given by `conditionList` **from the favorites folder**, where
    `conditionList` is a list of song IDs.
    """

    CLEAR_TEAM_COURSE_WITH_CHARACTER_OF_MINIMUM_RANK = 37
    """
    Clear a team course while equipping a character of minimum rank.
    """

class MapAreaConditionLogicalOperator(Enum):
    AND = 1
    OR = 2


class AvatarCategory(Enum):
    WEAR = 1
    HEAD = 2
    FACE = 3
    SKIN = 4
    ITEM = 5
    FRONT = 6
    BACK = 7

class ItemKind(IntEnum):
    NAMEPLATE = 1
    
    FRAME = 2
    """
    "Frame" is the background for the gauge/score/max combo display
    shown during gameplay. This item cannot be equipped (as of LUMINOUS PLUS)
    and is hardcoded to the current game's version.
    """

    TROPHY = 3
    SKILL = 4

    TICKET = 5
    """A statue is also a ticket."""

    PRESENT = 6
    MUSIC_UNLOCK = 7
    MAP_ICON = 8
    SYSTEM_VOICE = 9
    SYMBOL_CHAT = 10
    AVATAR_ACCESSORY = 11

    ULTIMA_UNLOCK = 12
    """This only applies to ULTIMA difficulties that are *not* unlocked by
    reaching S rank on EXPERT difficulty or above.
    """
    
    STAGE = 13


class FavoriteItemKind(IntEnum):
    MUSIC = 1
    RIVAL = 2
    CHARACTER = 3
