from dataclasses import dataclass

from Options import Choice, Toggle, DeathLink, DefaultOnToggle, TextChoice, Range, OptionDict, PerGameCommonOptions
from schema import Schema, And, Use, Optional

bosses = {
    "Heat Man": 0,
    "Air Man": 1,
    "Wood Man": 2,
    "Bubble Man": 3,
    "Quick Man": 4,
    "Flash Man": 5,
    "Metal Man": 6,
    "Crash Man": 7,
    "Mecha Dragon": 8,
    "Picopico-kun": 9,
    "Guts Tank": 10,
    "Boobeam Trap": 11,
    "Wily Machine 2": 12,
    "Alien": 13
}

weapons_to_id = {
    "Mega Buster": 0,
    "Atomic Fire": 1,
    "Air Shooter": 2,
    "Leaf Shield": 3,
    "Bubble Lead": 4,
    "Quick Boomerang": 5,
    "Metal Blade": 7,
    "Crash Bomber": 6,
    "Time Stopper": 8,
}


class EnergyLink(Toggle):
    """
    Enables EnergyLink support.
    When enabled, pickups dropped from enemies are sent to the EnergyLink pool, and healing/weapon energy/1-Ups can
    be requested from the EnergyLink pool.
    Some of the energy sent to the pool will be lost on transfer.
    """
    display_name = "EnergyLink"


class StartingRobotMaster(Choice):
    """
    The initial stage unlocked at the start.
    """
    display_name = "Starting Robot Master"
    option_heat_man = 0
    option_air_man = 1
    option_wood_man = 2
    option_bubble_man = 3
    option_quick_man = 4
    option_flash_man = 5
    option_metal_man = 6
    option_crash_man = 7
    default = "random"


class YokuJumps(Toggle):
    """
    When enabled, the player is expected to be able to perform the yoku block sequence in Heat Man's
    stage without Item 2.
    """
    display_name = "Yoku Block Jumps"


class EnableLasers(Toggle):
    """
    When enabled, the player is expected to complete (and acquire items within) the laser sections of Quick Man's
    stage without the Time Stopper.
    """
    display_name = "Enable Lasers"


class Consumables(Choice):
    """
    When enabled, e-tanks/1-ups/health/weapon energy will be added to the pool of items and included as checks.
    E-Tanks and 1-Ups add 20 checks to the pool.
    Weapon/Health Energy add 27 checks to the pool.
    """
    display_name = "Consumables"
    option_none = 0
    option_1up_etank = 1
    option_weapon_health = 2
    option_all = 3
    default = 1
    alias_true = 3
    alias_false = 0

    @classmethod
    def get_option_name(cls, value: int) -> str:
        if value == 1:
            return "1-Ups/E-Tanks"
        if value == 2:
            return "Weapon/Health Energy"
        return super().get_option_name(value)


class Quickswap(DefaultOnToggle):
    """
    When enabled, the player can quickswap through all received weapons by pressing Select.
    """
    display_name = "Quickswap"


class PaletteShuffle(TextChoice):
    """
    Change the color of Mega Man and the Robot Masters.
    None: The palettes are unchanged.
    Shuffled: Palette colors are shuffled amongst the robot masters.
    Randomized: Random (usually good) palettes are generated for each robot master.
    Singularity: one palette is generated and used for all robot masters.
    Supports custom palettes using HTML named colors in the
    following format: Mega Buster-Lavender|Violet;randomized
    The first value is the character whose palette you'd like to define, then separated by - is a set of 2 colors for
    that character. separate every color with a pipe, and separate every character as well as the remaining shuffle with
    a semicolon.
    """
    display_name = "Palette Shuffle"
    option_none = 0
    option_shuffled = 1
    option_randomized = 2
    option_singularity = 3


class EnemyWeaknesses(Toggle):
    """
    Randomizes the damage dealt to enemies by weapons. Friender will always take damage from the buster.
    """
    display_name = "Random Enemy Weaknesses"


class StrictWeaknesses(Toggle):
    """
    Only your starting Robot Master will take damage from the Mega Buster, the rest must be defeated with weapons.
    Weapons that only do 1-3 damage to bosses no longer deal damage (aside from Alien).
    """
    display_name = "Strict Boss Weaknesses"


class RandomWeaknesses(Choice):
    """
    None: Bosses will have their regular weaknesses.
    Shuffled: Weapon damage will be shuffled amongst the weapons, so Metal Blade may do Bubble Lead damage.
    Time Stopper will deplete half of a random Robot Master's HP.
    Randomized: Weapon damage will be fully randomized.
    """
    display_name = "Random Boss Weaknesses"
    option_none = 0
    option_shuffled = 1
    option_randomized = 2
    alias_false = 0
    alias_true = 2


class Wily5Requirement(Range):
    """Change the number of Robot Masters that are required to be defeated for
    the teleporter to the Wily Machine to appear."""
    display_name = "Wily 5 Requirement"
    default = 8
    range_start = 1
    range_end = 8


class WeaknessPlando(OptionDict):
    """
    Specify specific damage numbers for boss damage. Can be used even without strict/random weaknesses.
    plando_weakness:
        Robot Master:
            Weapon: Damage
    """
    display_name = "Plando Weaknesses"
    schema = Schema({
        Optional(And(str, Use(str.title), lambda s: s in bosses)): {
            And(str, Use(str.title), lambda s: s in weapons_to_id): And(int, lambda i: i in range(-1, 14))
        }
    })
    default = {}


class ReduceFlashing(Choice):
    """
    Reduce flashing seen in gameplay, such as the stage select and when defeating a Wily boss.
    Virtual Console: increases length of most flashes, changes some flashes from white to a dark gray.
    Minor: VC changes + decreasing the speed of Bubble/Metal Man stage animations.
    Full: VC changes + further decreasing the brightness of most flashes and
    disables stage animations for Metal/Bubble Man stages.
    """
    display_name = "Reduce Flashing"
    option_none = 0
    option_virtual_console = 1
    option_minor = 2
    option_full = 3
    default = 1


class RandomMusic(Choice):
    """
    Vanilla: music is unchanged
    Shuffled: stage and certain menu music is shuffled.
    Randomized: stage and certain menu music is randomly selected
    None: no music will play
    """
    display_name = "Random Music"
    option_vanilla = 0
    option_shuffled = 1
    option_randomized = 2
    option_none = 3

@dataclass
class MM2Options(PerGameCommonOptions):
    death_link: DeathLink
    energy_link: EnergyLink
    starting_robot_master: StartingRobotMaster
    consumables: Consumables
    yoku_jumps: YokuJumps
    enable_lasers: EnableLasers
    enemy_weakness: EnemyWeaknesses
    strict_weakness: StrictWeaknesses
    random_weakness: RandomWeaknesses
    wily_5_requirement: Wily5Requirement
    plando_weakness: WeaknessPlando
    palette_shuffle: PaletteShuffle
    quickswap: Quickswap
    reduce_flashing: ReduceFlashing
    random_music: RandomMusic