import * as mc from "@minecraft/server";
import * as utils from "../../utils/index";
import * as comp from "../components/index";
import { BotBase } from "../bot";
export const TELEPORT_MAX_FUEL = 99;
export const TELEPORT_FUEL_ITEM = "minecraft:chorus_fruit";
class portalRegistry {
    static saveRegistry() {
        utils.writeDynamicProperty(mc.world, "portal_registry", Object.fromEntries(this.registry));
        utils.mclog("Registry: " + JSON.stringify(Object.fromEntries(this.registry)), "portal_logs");
    }
    static init() {
        var _a;
        const entries = (_a = utils.readDynamicProperty(mc.world, "portal_registry")) !== null && _a !== void 0 ? _a : {};
        this.registry = new Map(Object.entries(entries));
        mc.system.afterEvents.scriptEventReceive.subscribe(event => {
            if (event.id === utils.addName("clear_teleport_registry")) {
                this.registry.clear();
                this.saveRegistry();
            }
        });
    }
    static addEntry(id, value) {
        this.registry.set(id, value);
        this.saveRegistry();
    }
    static hasEntry(id) {
        return this.registry.has(id);
    }
    static deleteEntry(id) {
        this.registry.delete(id);
        this.saveRegistry();
    }
    static updateEntry(id, key, value) {
        const entry = this.registry.get(id);
        if (entry) {
            entry[key] = value;
            this.registry.set(id, entry);
            this.saveRegistry();
        }
    }
    static getEntry(id, key) {
        const entry = this.registry.get(id);
        if (entry) {
            return new utils.Vector3(entry[key]);
        }
    }
}
portalRegistry.registry = new Map();
export class portalBot extends BotBase {
    constructor() {
        var _a;
        super(...arguments);
        this.registryId = (_a = utils.readDynamicProperty(this, "portal_registry_key")) !== null && _a !== void 0 ? _a : "";
        this.isTeleporting = false;
    }
    get RegistryId() {
        return this.registryId;
    }
    set RegistryId(v) {
        this.registryId = v;
        utils.writeDynamicProperty(this, "portal_registry_key", v);
    }
    onConstructed() {
        super.onConstructed();
        this.addActorComponent(comp.BotFuelComponent, { fuelItem: TELEPORT_FUEL_ITEM, max: TELEPORT_MAX_FUEL });
        this.addActorComponent(comp.BlockSnapComponent, { angle: 90 });
        // If this bot doesn't have it's registry assigned externally on creation, it is the original and its id is stored.
        utils.waitForEvent(5, () => this.register());
    }
    destructor() {
        if (!this.isTeleporting) {
            portalRegistry.deleteEntry(this.RegistryId);
        }
        super.destructor();
    }
    onNonFuelInteract(player) {
        player.teleport(this.location);
        player.playSound(utils.addName("menu.bot.open"));
        this.openTeleportMenu(player);
    }
    onFuelExhausted() {
        this.dimension.playSound(utils.addName("entity.bot.power_down"), this.location);
    }
    register() {
        if (this.RegistryId === "" || !portalRegistry.hasEntry(this.registryId)) {
            this.RegistryId = this.id;
            const origin = this.location.floor();
            const overworld = this.dimension.id === utils.nether.id ? origin.multiply(8) : origin;
            const nether = this.dimension.id === utils.nether.id ? origin : origin.divide(8);
            const the_end = this.dimension.id === utils.nether.id ? origin.multiply(8) : origin;
            overworld.y = origin.y;
            nether.y = origin.y;
            the_end.y = origin.y;
            portalRegistry.addEntry(this.id, { overworld, nether, the_end });
        }
    }
    openTeleportMenu(player) {
        player.playSound(utils.addName("entity.bot.open_menu"));
        new utils.MenuBuilder({
            type: "buttons",
            title: { translate: "ldz_240927:action.menu.title.ldz_240927:portal" },
            contents: [
                {
                    text: { translate: "dimension.dimensionName0" },
                    texture: "textures/ldz/240927/ui/overworld",
                    shouldHide: () => this.dimension.id === utils.overworld.id,
                    onClick: () => {
                        player.playSound(utils.addName("menu.bot.confirm"));
                        this.performTeleport(player, utils.overworld);
                    }
                },
                {
                    text: { translate: "dimension.dimensionName1" },
                    texture: "textures/ldz/240927/ui/nether",
                    shouldHide: () => this.dimension.id === utils.nether.id,
                    onClick: () => {
                        //player.dimension.playSound(utils.addName("entity.bot.confirm"), player.location);
                        player.playSound(utils.addName("menu.bot.confirm"));
                        this.performTeleport(player, utils.nether);
                    }
                },
                {
                    text: { translate: "dimension.dimensionName2" },
                    texture: "textures/ldz/240927/ui/the_end",
                    shouldHide: () => this.dimension.id === utils.end.id,
                    onClick: () => {
                        player.playSound(utils.addName("menu.bot.confirm"));
                        this.performTeleport(player, utils.end);
                    }
                },
            ]
        }).showMenuToPlayer(player);
    }
    async performTeleport(player, dimension) {
        var _a, _b;
        const destination = portalRegistry.getEntry(this.RegistryId, dimension.id.replace("minecraft:", ""));
        const currentFuel = this.Fuel;
        if (!destination)
            return;
        utils.mclog(`Teleporting to ${destination} in ${dimension.id} from key ${this.RegistryId}`, "portal_logs");
        player.runCommand('function ldz/240927/portal_bot/tp_fx');
        player.addEffect("resistance", 1000000, { amplifier: 255, showParticles: false });
        player.addEffect("levitation", 1000000, { amplifier: 0, showParticles: false });
        this.isTeleporting = true;
        utils.despawnOnReload(this);
        utils.waitForEvent(20, () => {
            if (this.isValid()) {
                this.remove();
            }
        });
        player.teleport(destination, { dimension });
        while (!((_a = dimension.getBlock(destination)) === null || _a === void 0 ? void 0 : _a.isValid()) && !((_b = dimension.getBlock(destination)) === null || _b === void 0 ? void 0 : _b.isAir)) {
            await utils.waitForTicks(1);
        }
        utils.mclog(`Dimension Loaded, Searching For Safe Ground`, "portal_logs");
        let safeDestination;
        await utils.iterateOverBlocks(dimension, destination, 8, (block) => {
            var _a, _b, _c;
            try {
                if (block.isAir && ((_a = block.above()) === null || _a === void 0 ? void 0 : _a.isAir) && !((_b = block.below()) === null || _b === void 0 ? void 0 : _b.isAir) && !((_c = block.below()) === null || _c === void 0 ? void 0 : _c.isLiquid)) {
                    safeDestination = new utils.Vector3(block.location);
                    return true;
                }
            }
            catch (error) { }
            return false;
        });
        if (safeDestination) {
            utils.mclog(`Found Safe Ground at ${safeDestination}`, "portal_logs");
            player.teleport(safeDestination.center());
            if (!safeDestination.approximatelyEqual(destination)) {
                utils.mclog(`Updating Registry Entry ${this.RegistryId} ${dimension.id}`, "portal_logs");
                portalRegistry.updateEntry(this.RegistryId, dimension.id.replace("minecraft:", ""), safeDestination);
            }
        }
        else {
            utils.mclog(`Failed to Find Safe Ground, Creating Platform At ${player.location}`, "portal_logs");
            player.runCommand("fill ~1 ~2 ~1 ~-1 ~-1 ~-1 air");
            player.runCommand("fill ~1 ~-1 ~1 ~-1 ~-1 ~-1 obsidian");
        }
        player.removeEffect("resistance");
        player.removeEffect("levitation");
        const actor = new portalBot(dimension.spawnEntity(utils.addName("portal_bot"), player.location.center()));
        actor.RegistryId = this.RegistryId;
        actor.Fuel = currentFuel - 1;
    }
}
portalRegistry.init();
utils.Actor.makeActors({ type: "ldz_240927:portal_bot" }, portalBot);
