from typing import Optional

from ...Class.newLocationClass import KH2Location
from ..LvupStats import DreamWeaponOffsets
from ..configDict import locationCategory, locationType
from ..inventory import ability
from ..inventory.item import InventoryItem
from .graph import LocationGraphBuilder, START_NODE, RequirementEdge
from ...Module.itemPlacementRestriction import ItemPlacementHelpers


def level_reward(
    level: int, description: str, vanilla: Optional[InventoryItem]
) -> KH2Location:
    vanilla_items: list[int] = []
    if vanilla is not None:
        vanilla_items.append(vanilla.id)
    return KH2Location(
        level,
        description,
        locationCategory.LEVEL,
        [locationType.Level],
        VanillaItems=vanilla_items,
    )


def make_graph(graph: LocationGraphBuilder):
    settings = graph.settings
    max_level = settings.max_level_checks

    vanilla_levels: dict[int, dict[int, InventoryItem]] = {
        50: {
            2: ability.ComboBoost,
            4: ability.ExperienceBoost,
            7: ability.MagicLockOn,
            9: ability.ReactionBoost,
            10: ability.ItemBoost,
            12: ability.LeafBracer,
            14: ability.FireBoost,
            15: ability.DriveBoost,
            17: ability.Draw,
            20: ability.CombinationBoost,
            23: ability.DamageDrive,
            25: ability.AirComboBoost,
            28: ability.BlizzardBoost,
            30: ability.DriveConverter,
            32: ability.NegativeCombo,
            34: ability.OnceMore,
            36: ability.FinishingPlus,
            39: ability.ThunderBoost,
            41: ability.Defender,
            44: ability.BerserkCharge,
            46: ability.Jackpot,
            48: ability.SecondChance,
            50: ability.DamageControl,
        },
        99: {
            7: ability.ComboBoost,
            9: ability.ExperienceBoost,
            12: ability.MagicLockOn,
            15: ability.ReactionBoost,
            17: ability.ItemBoost,
            20: ability.LeafBracer,
            23: ability.FireBoost,
            25: ability.DriveBoost,
            28: ability.Draw,
            31: ability.CombinationBoost,
            33: ability.DamageDrive,
            36: ability.AirComboBoost,
            39: ability.BlizzardBoost,
            41: ability.DriveConverter,
            44: ability.NegativeCombo,
            47: ability.OnceMore,
            49: ability.FinishingPlus,
            53: ability.ThunderBoost,
            59: ability.Defender,
            65: ability.BerserkCharge,
            73: ability.Jackpot,
            85: ability.SecondChance,
            99: ability.DamageControl,
        },
    }

    node_index = 0
    locations: list[str] = []
    current_location_list: list[KH2Location] = []

    already_added_level_to_group = False
    level_offsets = DreamWeaponOffsets()
    excluded_levels = settings.excluded_levels()
    for level in range(1, 100):
        level_description = f"Level {level}"

        if settings.split_levels:
            shield = level_offsets.get_shield_level(max_level, level)
            staff = level_offsets.get_staff_level(max_level, level)
            if shield and staff:
                level_description = f"Level Sw: {level} Sh: {shield} St: {staff}"

        vanilla_item: Optional[InventoryItem] = None
        if max_level in vanilla_levels and level in vanilla_levels[max_level]:
            vanilla_item = vanilla_levels[max_level][level]
        elif level in vanilla_levels[99]:
            vanilla_item = vanilla_levels[99][level]

        current_location_list.append(
            level_reward(level, level_description, vanilla_item)
        )

        if level not in excluded_levels:
            if already_added_level_to_group:
                locations.append(
                    graph.add_location(
                        f"LevelGroup-{node_index}", current_location_list
                    )
                )
                current_location_list = []
                node_index += 1
                already_added_level_to_group = False
            else:
                already_added_level_to_group = True

    # Add in the last group if there are any stragglers
    if len(current_location_list) > 0:
        locations.append(
            graph.add_location(f"LevelGroup-{node_index}", current_location_list)
        )

    for index, location in enumerate(locations):
        if index == 0:
            graph.add_edge(
                START_NODE,
                location,
                RequirementEdge(req=ItemPlacementHelpers.make_level_group_check(index)),
            )
        else:
            graph.add_edge(
                locations[index - 1],
                location,
                RequirementEdge(req=ItemPlacementHelpers.make_level_group_check(index)),
            )
