"""
Unit tests for yaml usecases we want to support
"""

from .test_base import Sc2SetupTestBase
from .. import get_all_missions, mission_tables, options
from ..item import item_groups, item_tables, item_names
from ..mission_tables import SC2Race, SC2Mission, SC2Campaign, MissionFlag
from ..options import (
    EnabledCampaigns, MasteryLocations, MissionOrder, EnableRaceSwapVariants, ShuffleCampaigns,
    ShuffleNoBuild, StarterUnit, RequiredTactics, KerriganPresence, KerriganLevelItemDistribution, GrantStoryTech,
    GrantStoryLevels, BasebustLocations, ChallengeLocations, DifficultyCurve, EnableMorphling, ExcludeOverpoweredItems,
    ExcludeVeryHardMissions, ExtraLocations, GenericUpgradeItems, GenericUpgradeResearch, GenericUpgradeResearchSpeedup,
    KerriganPrimalStatus, KeyMode, MissionOrderScouting, EnableMissionRaceBalancing,
    NovaGhostOfAChanceVariant, PreventativeLocations, SpeedrunLocations, TakeOverAIAllies, VanillaItemsOnly
)


class TestSupportedUseCases(Sc2SetupTestBase):
    def test_vanilla_all_campaigns_generates(self) -> None:
        world_options = {
            'mission_order': options.MissionOrder.option_vanilla,
            'enabled_campaigns': EnabledCampaigns.valid_keys,
        }

        self.generate_world(world_options)
        world_regions = [region.name for region in self.multiworld.regions if region.name != "Menu"]

        self.assertEqual(len(world_regions), 83, "Unexpected number of missions for vanilla mission order")

    def test_terran_with_nco_units_only_generates(self):
        world_options = {
            'enabled_campaigns': {
                SC2Campaign.WOL.campaign_name,
                SC2Campaign.NCO.campaign_name
            },
            'excluded_items': {
                item_groups.ItemGroupNames.TERRAN_UNITS: 0,
            },
            'unexcluded_items': {
                item_groups.ItemGroupNames.NCO_UNITS: 0,
            },
            'max_number_of_upgrades': 2,
        }

        self.generate_world(world_options)
        self.assertTrue(self.multiworld.itempool)
        world_item_names = [item.name for item in self.multiworld.itempool]

        self.assertIn(item_names.MARINE, world_item_names)
        self.assertIn(item_names.RAVEN, world_item_names)
        self.assertIn(item_names.LIBERATOR, world_item_names)
        self.assertIn(item_names.BATTLECRUISER, world_item_names)
        self.assertNotIn(item_names.DIAMONDBACK, world_item_names)
        self.assertNotIn(item_names.DIAMONDBACK_BURST_CAPACITORS, world_item_names)
        self.assertNotIn(item_names.VIKING, world_item_names)

    def test_nco_with_nobuilds_excluded_generates(self):
        world_options = {
            'enabled_campaigns': {
                SC2Campaign.NCO.campaign_name
            },
            'shuffle_no_build': options.ShuffleNoBuild.option_false,
            'mission_order': options.MissionOrder.option_mini_campaign,
        }

        self.generate_world(world_options)
        self.assertTrue(self.multiworld.itempool)
        missions = get_all_missions(self.world.custom_mission_order)

        self.assertNotIn(mission_tables.SC2Mission.THE_ESCAPE, missions)
        self.assertNotIn(mission_tables.SC2Mission.IN_THE_ENEMY_S_SHADOW, missions)
        for mission in missions:
            self.assertEqual(mission_tables.SC2Campaign.NCO, mission.campaign)

    def test_terran_with_nco_upgrades_units_only_generates(self):
        world_options = {
            'enabled_campaigns': {
                SC2Campaign.WOL.campaign_name,
                SC2Campaign.NCO.campaign_name
            },
            'mission_order': options.MissionOrder.option_vanilla_shuffled,
            'excluded_items': {
                item_groups.ItemGroupNames.TERRAN_ITEMS: 0,
            },
            'unexcluded_items': {
                item_groups.ItemGroupNames.NCO_MAX_PROGRESSIVE_ITEMS: 0,
                item_groups.ItemGroupNames.NCO_MIN_PROGRESSIVE_ITEMS: 1,
            },
            'excluded_missions': [
                # These missions have trouble fulfilling Terran Power Rating under these terms
                SC2Mission.SUPERNOVA.mission_name,
                SC2Mission.WELCOME_TO_THE_JUNGLE.mission_name,
                SC2Mission.TROUBLE_IN_PARADISE.mission_name,
            ],
            'mastery_locations': MasteryLocations.option_disabled,
        }

        self.generate_world(world_options)
        world_item_names = [item.name for item in self.multiworld.itempool + self.multiworld.precollected_items[1]]
        self.assertTrue(world_item_names)
        missions = get_all_missions(self.world.custom_mission_order)

        for mission in missions:
            self.assertIn(mission_tables.MissionFlag.Terran, mission.flags)
        self.assertIn(item_names.MARINE, world_item_names)
        self.assertIn(item_names.MARAUDER, world_item_names)
        self.assertIn(item_names.BUNKER, world_item_names)
        self.assertIn(item_names.BANSHEE, world_item_names)
        self.assertIn(item_names.BATTLECRUISER_ATX_LASER_BATTERY, world_item_names)
        self.assertIn(item_names.NOVA_C20A_CANISTER_RIFLE, world_item_names)
        self.assertGreaterEqual(world_item_names.count(item_names.BANSHEE_PROGRESSIVE_CROSS_SPECTRUM_DAMPENERS), 2)
        self.assertGreaterEqual(world_item_names.count(item_names.PROGRESSIVE_TERRAN_SHIP_WEAPON), 3)
        self.assertNotIn(item_names.MEDIC, world_item_names)
        self.assertNotIn(item_names.PSI_DISRUPTER, world_item_names)
        self.assertNotIn(item_names.BATTLECRUISER_PROGRESSIVE_MISSILE_PODS, world_item_names)
        self.assertNotIn(item_names.HELLION_INFERNAL_PLATING, world_item_names)
        self.assertNotIn(item_names.CELLULAR_REACTOR, world_item_names)
        self.assertNotIn(item_names.TECH_REACTOR, world_item_names)
    
    def test_nco_and_2_wol_missions_only_can_generate_with_vanilla_items_only(self) -> None:
        world_options = {
            'enabled_campaigns': {
                SC2Campaign.WOL.campaign_name,
                SC2Campaign.NCO.campaign_name
            },
            'excluded_missions': [
                mission.mission_name for mission in mission_tables.SC2Mission
                if mission.campaign == mission_tables.SC2Campaign.WOL
                    and mission.mission_name not in (mission_tables.SC2Mission.LIBERATION_DAY.mission_name, mission_tables.SC2Mission.THE_OUTLAWS.mission_name)
            ],
            'mission_order': options.MissionOrder.option_grid,
            'maximum_campaign_size': options.MaximumCampaignSize.range_end,
            'mastery_locations': options.MasteryLocations.option_disabled,
            'vanilla_items_only': True,
        }

        self.generate_world(world_options)
        world_item_names = [item.name for item in self.multiworld.itempool]

        self.assertTrue(item_names)
        self.assertNotIn(item_names.LIBERATOR, world_item_names)
        self.assertNotIn(item_names.MARAUDER_PROGRESSIVE_STIMPACK, world_item_names)
        self.assertNotIn(item_names.HELLION_HELLBAT, world_item_names)
        self.assertNotIn(item_names.BATTLECRUISER_CLOAK, world_item_names)
    
    def test_free_protoss_only_generates(self) -> None:
        world_options = {
            'enabled_campaigns': {
                SC2Campaign.PROPHECY.campaign_name,
                SC2Campaign.PROLOGUE.campaign_name
            },
            # todo(mm): Currently, these settings don't generate on grid because there are not enough EASY missions
            'mission_order': options.MissionOrder.option_vanilla_shuffled,
            'maximum_campaign_size': options.MaximumCampaignSize.range_end,
            'accessibility': 'locations',
        }

        self.generate_world(world_options)
        world_item_names = [item.name for item in self.multiworld.itempool]
        self.assertTrue(world_item_names)
        missions = get_all_missions(self.world.custom_mission_order)

        self.assertEqual(len(missions), 7, "Wrong number of missions in free protoss seed")
        for mission in missions:
            self.assertIn(mission.campaign, (mission_tables.SC2Campaign.PROLOGUE, mission_tables.SC2Campaign.PROPHECY))
        for item_name in world_item_names:
            self.assertIn(item_tables.item_table[item_name].race, (mission_tables.SC2Race.ANY, mission_tables.SC2Race.PROTOSS))

    def test_resource_filler_items_may_be_put_in_start_inventory(self) -> None:
        NUM_RESOURCE_ITEMS = 10
        world_options = {
            'start_inventory': {
                item_names.STARTING_MINERALS: NUM_RESOURCE_ITEMS,
                item_names.STARTING_VESPENE: NUM_RESOURCE_ITEMS,
                item_names.STARTING_SUPPLY: NUM_RESOURCE_ITEMS,
            },
        }

        self.generate_world(world_options)
        start_item_names = [item.name for item in self.multiworld.precollected_items[self.player]]

        self.assertEqual(start_item_names.count(item_names.STARTING_MINERALS), NUM_RESOURCE_ITEMS, "Wrong number of starting minerals in starting inventory")
        self.assertEqual(start_item_names.count(item_names.STARTING_VESPENE), NUM_RESOURCE_ITEMS, "Wrong number of starting vespene in starting inventory")
        self.assertEqual(start_item_names.count(item_names.STARTING_SUPPLY), NUM_RESOURCE_ITEMS, "Wrong number of starting supply in starting inventory")

    def test_excluding_protoss_excludes_campaigns_and_items(self) -> None:
        world_options = {
            'selected_races': {
                SC2Race.TERRAN.get_title(),
                SC2Race.ZERG.get_title(),
            },
            'enabled_campaigns': options.EnabledCampaigns.valid_keys,
            'mission_order': options.MissionOrder.option_grid,
        }

        self.generate_world(world_options)
        world_item_names = [item.name for item in self.multiworld.itempool]
        world_regions = [region.name for region in self.multiworld.regions]
        world_regions.remove('Menu')

        for item_name in world_item_names:
            self.assertNotEqual(item_tables.item_table[item_name].race, mission_tables.SC2Race.PROTOSS, f"{item_name} is a PROTOSS item!")
        for region in world_regions:
            self.assertNotIn(mission_tables.lookup_name_to_mission[region].campaign, 
                             (mission_tables.SC2Campaign.LOTV, mission_tables.SC2Campaign.PROPHECY, mission_tables.SC2Campaign.PROLOGUE),
                             f"{region} is a PROTOSS mission!")

    def test_excluding_terran_excludes_campaigns_and_items(self) -> None:
        world_options = {
            'selected_races': {
                SC2Race.ZERG.get_title(),
                SC2Race.PROTOSS.get_title(),
            },
            'enabled_campaigns': EnabledCampaigns.valid_keys,
            'mission_order': options.MissionOrder.option_grid,
        }

        self.generate_world(world_options)
        world_item_names = [item.name for item in self.multiworld.itempool]
        world_regions = [region.name for region in self.multiworld.regions]
        world_regions.remove('Menu')

        for item_name in world_item_names:
            self.assertNotEqual(item_tables.item_table[item_name].race, mission_tables.SC2Race.TERRAN,
                                f"{item_name} is a TERRAN item!")
        for region in world_regions:
            self.assertNotIn(mission_tables.lookup_name_to_mission[region].campaign,
                             (mission_tables.SC2Campaign.WOL, mission_tables.SC2Campaign.NCO),
                             f"{region} is a TERRAN mission!")

    def test_excluding_zerg_excludes_campaigns_and_items(self) -> None:
        world_options = {
            'selected_races': {
                SC2Race.TERRAN.get_title(),
                SC2Race.PROTOSS.get_title(),
            },
            'enabled_campaigns': EnabledCampaigns.valid_keys,
            'mission_order': options.MissionOrder.option_grid,
            'excluded_missions': [
                SC2Mission.THE_INFINITE_CYCLE.mission_name
            ]
        }

        self.generate_world(world_options)
        world_item_names = [item.name for item in self.multiworld.itempool]
        world_regions = [region.name for region in self.multiworld.regions]
        world_regions.remove('Menu')

        for item_name in world_item_names:
            self.assertNotEqual(item_tables.item_table[item_name].race, mission_tables.SC2Race.ZERG,
                                f"{item_name} is a ZERG item!")
        # have to manually exclude the only non-zerg HotS mission...
        for region in filter(lambda region: region != "With Friends Like These", world_regions):
            self.assertNotIn(mission_tables.lookup_name_to_mission[region].campaign,
                             ([mission_tables.SC2Campaign.HOTS]),
                             f"{region} is a ZERG mission!")

    def test_excluding_faction_on_vanilla_order_excludes_epilogue(self) -> None:
        world_options = {
            'selected_races': {
                SC2Race.TERRAN.get_title(),
                SC2Race.PROTOSS.get_title(),
            },
            'enabled_campaigns': EnabledCampaigns.valid_keys,
            'mission_order': options.MissionOrder.option_vanilla,
        }

        self.generate_world(world_options)
        world_regions = [region.name for region in self.multiworld.regions]
        world_regions.remove('Menu')

        for region in world_regions:
            self.assertNotIn(mission_tables.lookup_name_to_mission[region].campaign,
                             ([mission_tables.SC2Campaign.EPILOGUE]),
                             f"{region} is an epilogue mission!")

    def test_race_swap_pick_one_has_correct_length_and_includes_swaps(self) -> None:
        world_options = {
            'selected_races': options.SelectedRaces.valid_keys,
            'enable_race_swap': options.EnableRaceSwapVariants.option_pick_one,
            'enabled_campaigns': {
                SC2Campaign.WOL.campaign_name,
            },
            'mission_order': options.MissionOrder.option_grid,
            'excluded_missions': [mission_tables.SC2Mission.ZERO_HOUR.mission_name],
        }

        self.generate_world(world_options)
        world_regions = [region.name for region in self.multiworld.regions]
        world_regions.remove('Menu')
        NUM_WOL_MISSIONS = len([mission for mission in SC2Mission if mission.campaign == SC2Campaign.WOL and MissionFlag.RaceSwap not in mission.flags])
        races = set(mission_tables.lookup_name_to_mission[mission].race for mission in world_regions)

        self.assertEqual(len(world_regions), NUM_WOL_MISSIONS)
        self.assertTrue(SC2Race.ZERG in races or SC2Race.PROTOSS in races)

    def test_start_inventory_upgrade_level_includes_only_correct_bundle(self) -> None:
        world_options = {
            'start_inventory': {
                item_groups.ItemGroupNames.TERRAN_GENERIC_UPGRADES: 1,
            },
            'locked_items': {
                # One unit of each class to guarantee upgrades are available
                item_names.MARINE: 1,
                item_names.VULTURE: 1,
                item_names.BANSHEE: 1,
            },
            'generic_upgrade_items': options.GenericUpgradeItems.option_bundle_unit_class,
            'selected_races': {
                SC2Race.TERRAN.get_title(),
            },
            'enable_race_swap': options.EnableRaceSwapVariants.option_disabled,
            'enabled_campaigns': {
                SC2Campaign.WOL.campaign_name,
            },
            'mission_order': options.MissionOrder.option_grid,
        }
        self.generate_world(world_options)
        self.assertTrue(self.multiworld.itempool)
        world_item_names = [item.name for item in self.multiworld.itempool]
        start_inventory = [item.name for item in self.multiworld.precollected_items[self.player]]

        # Start inventory
        self.assertIn(item_names.PROGRESSIVE_TERRAN_INFANTRY_UPGRADE, start_inventory)
        self.assertIn(item_names.PROGRESSIVE_TERRAN_VEHICLE_UPGRADE, start_inventory)
        self.assertIn(item_names.PROGRESSIVE_TERRAN_SHIP_UPGRADE, start_inventory)
        self.assertNotIn(item_names.PROGRESSIVE_TERRAN_INFANTRY_WEAPON, start_inventory)
        self.assertNotIn(item_names.PROGRESSIVE_TERRAN_INFANTRY_ARMOR, start_inventory)
        self.assertNotIn(item_names.PROGRESSIVE_TERRAN_VEHICLE_WEAPON, start_inventory)
        self.assertNotIn(item_names.PROGRESSIVE_TERRAN_VEHICLE_ARMOR, start_inventory)
        self.assertNotIn(item_names.PROGRESSIVE_TERRAN_SHIP_WEAPON, start_inventory)
        self.assertNotIn(item_names.PROGRESSIVE_TERRAN_SHIP_ARMOR, start_inventory)
        self.assertNotIn(item_names.PROGRESSIVE_TERRAN_ARMOR_UPGRADE, start_inventory)

        # Additional items in pool -- standard tactics will require additional levels
        self.assertIn(item_names.PROGRESSIVE_TERRAN_INFANTRY_UPGRADE, world_item_names)
        self.assertIn(item_names.PROGRESSIVE_TERRAN_VEHICLE_UPGRADE, world_item_names)
        self.assertIn(item_names.PROGRESSIVE_TERRAN_SHIP_UPGRADE, world_item_names)
        self.assertNotIn(item_names.PROGRESSIVE_TERRAN_INFANTRY_WEAPON, world_item_names)
        self.assertNotIn(item_names.PROGRESSIVE_TERRAN_INFANTRY_ARMOR, world_item_names)
        self.assertNotIn(item_names.PROGRESSIVE_TERRAN_VEHICLE_WEAPON, world_item_names)
        self.assertNotIn(item_names.PROGRESSIVE_TERRAN_VEHICLE_ARMOR, world_item_names)
        self.assertNotIn(item_names.PROGRESSIVE_TERRAN_SHIP_WEAPON, world_item_names)
        self.assertNotIn(item_names.PROGRESSIVE_TERRAN_SHIP_ARMOR, world_item_names)
        self.assertNotIn(item_names.PROGRESSIVE_TERRAN_ARMOR_UPGRADE, world_item_names)

    def test_kerrigan_max_active_abilities(self):
        target_number: int = 8
        world_options = {
            **self.ALL_CAMPAIGNS,
            'mission_order': options.MissionOrder.option_grid,
            'maximum_campaign_size': options.MaximumCampaignSize.range_end,
            'selected_races': {
                SC2Race.ZERG.get_title(),
            },
            'enable_race_swap': options.EnableRaceSwapVariants.option_shuffle_all,
            'kerrigan_max_active_abilities': target_number,
        }

        self.generate_world(world_options)
        world_item_names = [item.name for item in self.multiworld.itempool]
        kerrigan_actives = [item_name for item_name in world_item_names if item_name in item_groups.kerrigan_active_abilities]

        self.assertLessEqual(len(kerrigan_actives), target_number)

    def test_kerrigan_max_passive_abilities(self):
        target_number: int = 3
        world_options = {
            **self.ALL_CAMPAIGNS,
            'mission_order': options.MissionOrder.option_grid,
            'maximum_campaign_size': options.MaximumCampaignSize.range_end,
            'selected_races': {
                SC2Race.ZERG.get_title(),
            },
            'enable_race_swap': options.EnableRaceSwapVariants.option_shuffle_all,
            'kerrigan_max_passive_abilities': target_number,
        }

        self.generate_world(world_options)
        world_item_names = [item.name for item in self.multiworld.itempool]
        kerrigan_passives = [item_name for item_name in world_item_names if item_name in item_groups.kerrigan_passives]

        self.assertLessEqual(len(kerrigan_passives), target_number)

    def test_spear_of_adun_max_active_abilities(self):
        target_number: int = 8
        world_options = {
            **self.ALL_CAMPAIGNS,
            'mission_order': options.MissionOrder.option_grid,
            'maximum_campaign_size': options.MaximumCampaignSize.range_end,
            'selected_races': {
                SC2Race.PROTOSS.get_title(),
            },
            'enable_race_swap': options.EnableRaceSwapVariants.option_shuffle_all,
            'spear_of_adun_max_active_abilities': target_number,
        }

        self.generate_world(world_options)
        world_item_names = [item.name for item in self.multiworld.itempool]
        spear_of_adun_actives = [item_name for item_name in world_item_names if item_name in item_tables.spear_of_adun_calldowns]

        self.assertLessEqual(len(spear_of_adun_actives), target_number)


    def test_spear_of_adun_max_autocasts(self):
        target_number: int = 2
        world_options = {
            **self.ALL_CAMPAIGNS,
            'mission_order': options.MissionOrder.option_grid,
            'maximum_campaign_size': options.MaximumCampaignSize.range_end,
            'selected_races': {
                SC2Race.PROTOSS.get_title(),
            },
            'enable_race_swap': options.EnableRaceSwapVariants.option_shuffle_all,
            'spear_of_adun_max_passive_abilities': target_number,
        }

        self.generate_world(world_options)
        world_item_names = [item.name for item in self.multiworld.itempool]
        spear_of_adun_autocasts = [item_name for item_name in world_item_names if item_name in item_tables.spear_of_adun_castable_passives]

        self.assertLessEqual(len(spear_of_adun_autocasts), target_number)


    def test_nova_max_weapons(self):
        target_number: int = 3
        world_options = {
            **self.ALL_CAMPAIGNS,
            'mission_order': options.MissionOrder.option_grid,
            'maximum_campaign_size': options.MaximumCampaignSize.range_end,
            'selected_races': {
                SC2Race.TERRAN.get_title(),
            },
            'enable_race_swap': options.EnableRaceSwapVariants.option_shuffle_all,
            'nova_max_weapons': target_number,
        }

        self.generate_world(world_options)
        world_item_names = [item.name for item in self.multiworld.itempool]
        nova_weapons = [item_name for item_name in world_item_names if item_name in item_groups.nova_weapons]

        self.assertLessEqual(len(nova_weapons), target_number)


    def test_nova_max_gadgets(self):
        target_number: int = 3
        world_options = {
            **self.ALL_CAMPAIGNS,
            'mission_order': options.MissionOrder.option_grid,
            'maximum_campaign_size': options.MaximumCampaignSize.range_end,
            'selected_races': {
                SC2Race.TERRAN.get_title(),
            },
            'enable_race_swap': options.EnableRaceSwapVariants.option_shuffle_all,
            'nova_max_gadgets': target_number,
        }

        self.generate_world(world_options)
        world_item_names = [item.name for item in self.multiworld.itempool]
        nova_gadgets = [item_name for item_name in world_item_names if item_name in item_groups.nova_gadgets]

        self.assertLessEqual(len(nova_gadgets), target_number)
    
    def test_mercs_only(self) -> None:
        world_options = {
            **self.ALL_CAMPAIGNS,
            'selected_races': [
                SC2Race.TERRAN.get_title(),
                SC2Race.ZERG.get_title(),
            ],
            'required_tactics': options.RequiredTactics.option_any_units,
            'excluded_items': {
                item_groups.ItemGroupNames.TERRAN_UNITS: 0,
                item_groups.ItemGroupNames.ZERG_UNITS: 0,
            },
            'unexcluded_items': {
                item_groups.ItemGroupNames.TERRAN_MERCENARIES: 0,
                item_groups.ItemGroupNames.ZERG_MERCENARIES: 0,
            },
            'start_inventory': {
                item_names.PROGRESSIVE_FAST_DELIVERY: 1,
                item_names.ROGUE_FORCES: 1,
                item_names.UNRESTRICTED_MUTATION: 1,
                item_names.EVOLUTIONARY_LEAP: 1,
            },
            'mission_order': options.MissionOrder.option_grid,
            'excluded_missions': [
                SC2Mission.ENEMY_WITHIN.mission_name,  # Requires a unit for Niadra to build
            ],
        }
        self.generate_world(world_options)
        world_item_names = [item.name for item in self.multiworld.itempool]
        terran_nonmerc_units = tuple(
            item_name
            for item_name in world_item_names
            if item_name in item_groups.terran_units and item_name not in item_groups.terran_mercenaries
        )
        zerg_nonmerc_units = tuple(
            item_name
            for item_name in world_item_names
            if item_name in item_groups.zerg_units and item_name not in item_groups.zerg_mercenaries
        )

        self.assertTupleEqual(terran_nonmerc_units, ())
        self.assertTupleEqual(zerg_nonmerc_units, ())

    def test_zerg_hots_no_terran_items(self) -> None:
        # The actual situation the bug got caught
        world_options = {
            'basebust_locations': BasebustLocations.option_enabled,
            'challenge_locations': ChallengeLocations.option_enabled,
            'difficulty_curve': DifficultyCurve.option_standard,
            'enable_morphling': EnableMorphling.option_false,
            'enable_race_swap': EnableRaceSwapVariants.option_disabled,
            'enabled_campaigns': [SC2Campaign.HOTS.campaign_name],
            'ensure_generic_items': 25,
            'exclude_overpowered_items': ExcludeOverpoweredItems.option_false,
            'exclude_very_hard_missions': ExcludeVeryHardMissions.option_default,
            'excluded_missions': [
                SC2Mission.SUPREME.mission_name
            ],
            'extra_locations': ExtraLocations.option_enabled,
            'generic_upgrade_items': GenericUpgradeItems.option_individual_items,
            'generic_upgrade_missions': 0,
            'generic_upgrade_research': GenericUpgradeResearch.option_auto_in_no_build,
            'generic_upgrade_research_speedup': GenericUpgradeResearchSpeedup.option_false,
            'grant_story_levels': GrantStoryLevels.option_disabled,
            'grant_story_tech': GrantStoryTech.option_no_grant,
            'kerrigan_level_item_distribution': KerriganLevelItemDistribution.option_size_14,
            'kerrigan_level_item_sum': 86,
            'kerrigan_levels_per_mission_completed': 0,
            'kerrigan_levels_per_mission_completed_cap': -1,
            'kerrigan_max_active_abilities': 12,
            'kerrigan_max_passive_abilities': 5,
            'kerrigan_presence': KerriganPresence.option_vanilla,
            'kerrigan_primal_status': KerriganPrimalStatus.option_vanilla,
            'kerrigan_total_level_cap': -1,
            'key_mode': KeyMode.option_progressive_questlines,
            'mastery_locations': MasteryLocations.option_disabled,
            'max_number_of_upgrades': -1,
            'max_upgrade_level': 4,
            'maximum_campaign_size': 40,
            'min_number_of_upgrades': 2,
            'mission_order': MissionOrder.option_mini_campaign,
            'mission_order_scouting': MissionOrderScouting.option_none,
            'mission_race_balancing': EnableMissionRaceBalancing.option_semi_balanced,
            'nova_ghost_of_a_chance_variant': NovaGhostOfAChanceVariant.option_wol,
            'preventative_locations': PreventativeLocations.option_enabled,
            'required_tactics': RequiredTactics.option_standard,
            'shuffle_campaigns': ShuffleCampaigns.option_true,
            'shuffle_no_build': ShuffleNoBuild.option_true,
            'speedrun_locations': SpeedrunLocations.option_disabled,
            'start_primary_abilities': 0,
            'starter_unit': StarterUnit.option_balanced,
            'starting_supply_per_item': 2,
            'take_over_ai_allies': TakeOverAIAllies.option_false,
            'vanilla_items_only': VanillaItemsOnly.option_false,
            'victory_cache': 0,
        }
        self.generate_world(world_options)

        world_item_names = [item.name for item in self.multiworld.itempool]

        self.assertNotIn(item_names.COMMAND_CENTER_SCANNER_SWEEP, world_item_names)
        self.assertNotIn(item_names.COMMAND_CENTER_EXTRA_SUPPLIES, world_item_names)
        self.assertNotIn(item_names.ULTRA_CAPACITORS, world_item_names)
        self.assertNotIn(item_names.ORBITAL_DEPOTS, world_item_names)
        self.assertNotIn(item_names.DOMINION_TROOPER, world_item_names)

    def test_all_kerrigan_missions_are_nobuild_and_grant_story_tech_is_on(self) -> None:
        # The actual situation the bug got caught
        world_options = {
            'mission_order': MissionOrder.option_vanilla_shuffled,
            'selected_races': [
                SC2Race.TERRAN.get_title(),
                SC2Race.ZERG.get_title(),
                SC2Race.PROTOSS.get_title(),
            ],
            'enabled_campaigns': [
                SC2Campaign.WOL.campaign_name,
                SC2Campaign.PROPHECY.campaign_name,
                SC2Campaign.HOTS.campaign_name,
                SC2Campaign.PROLOGUE.campaign_name,
                SC2Campaign.LOTV.campaign_name,
                SC2Campaign.EPILOGUE.campaign_name,
                SC2Campaign.NCO.campaign_name,
            ],
            'enable_race_swap': EnableRaceSwapVariants.option_shuffle_all_non_vanilla, # Causes no build Kerrigan missions to be present, only nobuilds remain
            'shuffle_campaigns': ShuffleCampaigns.option_true,
            'shuffle_no_build': ShuffleNoBuild.option_true,
            'starter_unit': StarterUnit.option_balanced,
            'required_tactics': RequiredTactics.option_standard,
            'kerrigan_presence': KerriganPresence.option_vanilla,
            'kerrigan_levels_per_mission_completed': 0,
            'kerrigan_levels_per_mission_completed_cap': -1,
            'kerrigan_level_item_sum': 87,
            'kerrigan_level_item_distribution': KerriganLevelItemDistribution.option_size_7,
            'kerrigan_total_level_cap': -1,
            'start_primary_abilities': 0,
            'grant_story_tech': GrantStoryTech.option_grant,
            'grant_story_levels': GrantStoryLevels.option_additive,
        }
        self.generate_world(world_options)
        # Just check that the world itself generates under those rules and no exception is thrown
