from typing import Set

from ..AutoWorld import World, LogicMixin
from .Items import item_table, default_pool
from .Locations import lookup_name_to_id
from .Rules import set_rules, location_rules
from .Regions import locations_by_region, connectors
from .Options import options
from BaseClasses import Region, Item, Location, RegionType, Entrance


class OriBlindForest(World):
    game: str = "Ori and the Blind Forest"

    topology_present = True

    item_name_to_id = item_table
    location_name_to_id = lookup_name_to_id

    options = options

    hidden = True

    def generate_early(self):
        logic_sets = {"casual-core"}
        for logic_set in location_rules:
            if logic_set != "casual-core" and getattr(self.world, logic_set.replace("-", "_")):
                logic_sets.add(logic_set)
        self.logic_sets = logic_sets

    set_rules = set_rules

    def create_region(self, name: str):
        return Region(name, RegionType.Generic, name, self.player, self.world)

    def create_regions(self):
        world = self.world
        menu = self.create_region("Menu")
        world.regions.append(menu)
        start = Entrance(self.player, "Start Game", menu)
        menu.exits.append(start)

        # workaround for now, remove duplicate locations
        already_placed_locations = set()

        for region_name, locations in locations_by_region.items():
            locations -= already_placed_locations
            already_placed_locations |= locations
            region = self.create_region(region_name)
            if region_name == "SunkenGladesRunaway":  # starting point
                start.connect(region)
            region.locations = {Location(self.player, location, lookup_name_to_id[location], region)
                                for location in locations}
            world.regions.append(region)

        for region_name, exits in connectors.items():
            parent = world.get_region(region_name, self.player)
            for exit in exits:
                connection = Entrance(self.player, exit, parent)
                connection.connect(world.get_region(exit, self.player))
                parent.exits.append(connection)

    def generate_basic(self):
        for item_name, count in default_pool.items():
            self.world.itempool.extend([self.create_item(item_name)] * count)

    def create_item(self, name: str) -> Item:
        return Item(name, not name.startswith("EX"), item_table[name], self.player)


class OriBlindForestLogic(LogicMixin):
    def _oribf_has_all(self, items: Set[str], player:int):
        return all(self.prog_items[item, player] if type(item) == str
                   else self.prog_items[item[0], player] >= item[1] for item in items)