import logging
import os
from Utils import __version__
from jinja2 import Template
import yaml
import json

from worlds.AutoWorld import AutoWorldRegister
import Options

target_folder = os.path.join("WebHostLib", "static", "generated")

handled_in_js = {"start_inventory", "local_items", "non_local_items", "start_hints", "start_location_hints",
                 "exclude_locations"}


def create():
    os.makedirs(os.path.join(target_folder, 'configs'), exist_ok=True)

    def dictify_range(option):
        data = {option.range_start: 0, option.range_end: 0, "random": 0, "random-low": 0, "random-high": 0,
                option.default: 50}
        notes = {
            option.range_start: "minimum value",
            option.range_end: "maximum value"
        }
        return data, notes

    def default_converter(default_value):
        if isinstance(default_value, (set, frozenset)):
            return list(default_value)
        return default_value

    weighted_settings = {
        "baseOptions": {
            "description": "Generated by https://archipelago.gg/",
            "name": "Player",
            "game": {},
        },
        "games": {},
    }

    for game_name, world in AutoWorldRegister.world_types.items():

        all_options = {**world.options, **Options.per_game_common_options}
        res = Template(open(os.path.join("WebHostLib", "templates", "options.yaml")).read()).render(
            options=all_options,
            __version__=__version__, game=game_name, yaml_dump=yaml.dump,
            dictify_range=dictify_range, default_converter=default_converter,
        )

        with open(os.path.join(target_folder, 'configs', game_name + ".yaml"), "w") as f:
            f.write(res)

        # Generate JSON files for player-settings pages
        player_settings = {
            "baseOptions": {
                "description": "Generated by https://archipelago.gg/",
                "game": game_name,
                "name": "Player",
            },
        }

        game_options = {}
        for option_name, option in all_options.items():
            if option_name in handled_in_js:
                pass

            elif option.options:
                game_options[option_name] = this_option = {
                    "type": "select",
                    "displayName": option.display_name if hasattr(option, "display_name") else option_name,
                    "description": option.__doc__ if option.__doc__ else "Please document me!",
                    "defaultValue": None,
                    "options": []
                }

                for sub_option_id, sub_option_name in option.name_lookup.items():
                    this_option["options"].append({
                        "name": option.get_option_name(sub_option_id),
                        "value": sub_option_name,
                    })

                    if sub_option_id == option.default:
                        this_option["defaultValue"] = sub_option_name

                this_option["options"].append({
                    "name": "Random",
                    "value": "random",
                })

            elif hasattr(option, "range_start") and hasattr(option, "range_end"):
                game_options[option_name] = {
                    "type": "range",
                    "displayName": option.display_name if hasattr(option, "display_name") else option_name,
                    "description": option.__doc__ if option.__doc__ else "Please document me!",
                    "defaultValue": option.default if hasattr(option, "default") else option.range_start,
                    "min": option.range_start,
                    "max": option.range_end,
                }

            elif getattr(option, "verify_item_name", False):
                game_options[option_name] = {
                    "type": "items-list",
                    "displayName": option.display_name if hasattr(option, "display_name") else option_name,
                    "description": option.__doc__ if option.__doc__ else "Please document me!",
                }

            elif getattr(option, "verify_location_name", False):
                game_options[option_name] = {
                    "type": "locations-list",
                    "displayName": option.display_name if hasattr(option, "display_name") else option_name,
                    "description": option.__doc__ if option.__doc__ else "Please document me!",
                }

            elif hasattr(option, "valid_keys"):
                if option.valid_keys:
                    game_options[option_name] = {
                        "type": "custom-list",
                        "displayName": option.display_name if hasattr(option, "display_name") else option_name,
                        "description": option.__doc__ if option.__doc__ else "Please document me!",
                        "options": list(option.valid_keys),
                    }

            else:
                logging.debug(f"{option} not exported to Web Settings.")

        player_settings["gameOptions"] = game_options

        os.makedirs(os.path.join(target_folder, 'player-settings'), exist_ok=True)

        with open(os.path.join(target_folder, 'player-settings', game_name + ".json"), "w") as f:
            json.dump(player_settings, f, indent=2, separators=(',', ': '))

        if not world.hidden and world.web.settings_page is True:
            weighted_settings["baseOptions"]["game"][game_name] = 0
            weighted_settings["games"][game_name] = {}
            weighted_settings["games"][game_name]["gameSettings"] = game_options
            weighted_settings["games"][game_name]["gameItems"] = tuple(world.item_names)
            weighted_settings["games"][game_name]["gameLocations"] = tuple(world.location_names)

    with open(os.path.join(target_folder, 'weighted-settings.json'), "w") as f:
        json.dump(weighted_settings, f, indent=2, separators=(',', ': '))
