import OptionsTransAPResource from "../../resource/OptionsTransAPResource.js";
import {
    translateLocation
} from "./APNameTranslator.js";

const trans = OptionsTransAPResource.get();

export function translateAPSettings(data = {}) {
    const target = {
        areaActiveLists: {},
        options: {}
    };
    const errors = [];

    const settingsTrans = trans["settings"];
    const dungeons = trans["dungeons"];
    const tricks = trans["tricks"];

    const {
        spawn_positions = 0,
        // "logic_tricks" is the old apworld's key; "allowed_tricks"/"advanced_allowed_tricks" are the new
        // apworld's replacements. Only one set will ever be present for a given connection - merge them all
        // into a single list so both apworld versions work through the same matching logic below.
        logic_tricks = [],
        allowed_tricks = [],
        advanced_allowed_tricks = [],
        dungeon_shortcuts = 0,
        dungeon_shortcuts_list = [],
        // Only populated (and only needed) for dungeon_shortcuts === 3 ("random"), where the raw enum gives no
        // per-dungeon detail and the actual resolved list only exists nested under generation_results.
        generation_results = {},
        mq_dungeons_mode = 0,
        mq_dungeons_list = [],
        mq_dungeons_count = 0,
        exclude_locations = [],
        ...rest_data
    } = data;

    // spawn positions
    target.options["shuffle_spawn_child"] = !!(spawn_positions & 1);
    target.options["shuffle_spawn_adult"] = !!(spawn_positions >> 1 & 1);

    // tricks
    const activeAPTricks = [...logic_tricks, ...allowed_tricks, ...advanced_allowed_tricks]
        .map((entry) => entry.toLowerCase());
    for (const [apTrick, trick] of Object.entries(tricks)) {
        target.options[trick] = activeAPTricks.includes(apTrick);
    }

    // dungeon shortcuts
    if (dungeon_shortcuts === 0) {
        for (const dungeonName in dungeons) {
            const internalName = dungeons[dungeonName];
            target.options[`dungeon_shortcuts.${internalName}`] = false;
        }
    } else if (dungeon_shortcuts === 1) {
        for (const dungeonName in dungeons) {
            const internalName = dungeons[dungeonName];
            target.options[`dungeon_shortcuts.${internalName}`] = dungeon_shortcuts_list.includes(dungeonName);
        }
    } else if (dungeon_shortcuts === 2) {
        for (const dungeonName in dungeons) {
            const internalName = dungeons[dungeonName];
            target.options[`dungeon_shortcuts.${internalName}`] = true;
        }
    } else if (dungeon_shortcuts === 3) {
        // "random" - the enum alone doesn't say which dungeons were picked, the resolved list lives here instead.
        const resolvedShortcuts = generation_results.dungeon_shortcuts ?? [];
        for (const dungeonName in dungeons) {
            const internalName = dungeons[dungeonName];
            target.options[`dungeon_shortcuts.${internalName}`] = resolvedShortcuts.includes(dungeonName);
        }
    }

    // mq dungeons
    if (mq_dungeons_mode === 0 || (mq_dungeons_mode === 3 && mq_dungeons_count === 0)) {
        for (const dungeonName in dungeons) {
            const internalName = dungeons[dungeonName];
            target.areaActiveLists[internalName] = "v";
        }
    } else if (mq_dungeons_mode === 1 || (mq_dungeons_mode === 3 && mq_dungeons_count === 12)) {
        for (const dungeonName in dungeons) {
            const internalName = dungeons[dungeonName];
            target.areaActiveLists[internalName] = "mq";
        }
    } else if (mq_dungeons_mode === 2) {
        for (const dungeonName in dungeons) {
            const internalName = dungeons[dungeonName];
            target.areaActiveLists[internalName] = mq_dungeons_list.includes(dungeonName) ? "mq" : "v";
        }
    }

    // exclude locations
    for (const name of exclude_locations) {
        const internalName = translateLocation(name);
        target.options[`excluded_location[${internalName}]`] = true;
    }

    // other settings
    for (const [key, value] of Object.entries(rest_data)) {
        try {
            const transData = settingsTrans[key];
            if (transData == null) {
                errors.push(`no valid translation found for option "${key}"`);
                continue;
            } else if (transData === false) {
                // ignore key
                continue;
            } else {
                const parsedValue = parseInt(value) || 0;
                if (typeof transData === "string") {
                    target.options[transData] = parsedValue;
                } else {
                    const {name, values, overwrite = false} = transData;
                    const transValue = values[parsedValue];
                    if (transValue == null) {
                        // ignore value
                        continue;
                    } else if (overwrite || target.options[name] == null) {
                        target.options[name] = transValue;
                    }
                }
            }
        } catch (err) {
            errors.push(err);
        }
    }

    // "bombchus_in_logic" no longer exists as an apworld option as of the 9.1.0 beta - bombchu availability is
    // now applied unconditionally in the world's own rules, i.e. always "in logic". Only fall back when the key
    // genuinely wasn't present in slot_data (older apworlds that still send it are handled by the map above and
    // must not be overwritten here).
    if (target.options.bombchu_logic == null) {
        target.options.bombchu_logic = true;
    }

    return [target, errors];
}

window.translateAPSlotData = translateAPSettings;
