import { world, } from "@minecraft/server";
import { ActionFormData } from "@minecraft/server-ui";
import ScriptingModule from "./scriptingModule";
import { ActionForm, ModalForm } from "./class/form";
import { forms } from "../config/forms/_index"; // Import forms configuration
import { namespace } from "../config/_config";
export default class FormModule extends ScriptingModule {
    constructor() {
        super("FormModule");
        this.actionForms = new Map();
        this.modalForms = new Map();
        this.triggers = new Map();
        this.references = new Map();
        this.navigationStack = [];
        this.mainForms = new Map();
        this.currentFormOpenedViaInteraction = false;
        this.handleItemUse = (event) => {
            const player = event.source;
            const itemTypeId = event.itemStack.typeId;
            if (!this.triggers.has(itemTypeId)) {
                return;
            }
            const entitiesHit = player.getEntitiesFromViewDirection({ maxDistance: 6 });
            for (const hit of entitiesHit) {
                const form = this.getInteractionForEntity(hit.entity.typeId, itemTypeId);
                if (form) {
                    this.showForm(player, form.id, false, true);
                    return;
                }
            }
            const blockHit = player.getBlockFromViewDirection({ maxDistance: 6 });
            if (blockHit) {
                const form = this.getInteractionForBlock(blockHit.block.typeId, itemTypeId);
                if (form) {
                    this.showForm(player, form.id, false, true);
                    return;
                }
            }
            const formIds = this.triggers.get(itemTypeId);
            if (formIds && formIds.length > 0) {
                const mainFormId = this.mainForms.get(itemTypeId);
                if (mainFormId) {
                    this.showForm(player, mainFormId, true);
                }
                else if (formIds.length === 1) {
                    this.showForm(player, formIds[0], true);
                }
                else {
                    this.showFormSelector(player, formIds, true);
                }
            }
        };
    }
    onInitialize() {
        world.afterEvents.itemUse.subscribe(this.handleItemUse);
        this.registerForms();
    }
    getInteractionForEntity(typeId, itemTypeId) {
        for (const form of this.actionForms.values()) {
            if (form.options.interact?.entities?.includes(typeId) &&
                this.triggers.get(itemTypeId)?.includes(form.id)) {
                return form;
            }
        }
        for (const form of this.modalForms.values()) {
            if (form.options.interact?.entities?.includes(typeId) &&
                this.triggers.get(itemTypeId)?.includes(form.id)) {
                return form;
            }
        }
        return null;
    }
    getInteractionForBlock(typeId, itemTypeId) {
        for (const form of this.actionForms.values()) {
            if (form.options.interact?.blocks?.includes(typeId) &&
                this.triggers.get(itemTypeId)?.includes(form.id)) {
                return form;
            }
        }
        for (const form of this.modalForms.values()) {
            if (form.options.interact?.blocks?.includes(typeId) &&
                this.triggers.get(itemTypeId)?.includes(form.id)) {
                return form;
            }
        }
        return null;
    }
    async showFormSelector(player, formIds, isMain = false) {
        if (isMain) {
            this.navigationStack = [];
        }
        const selector = new ActionFormData().title("Select a guide").body("Choose a guide to view:");
        formIds.forEach((id) => {
            const form = this.actionForms.get(id) || this.modalForms.get(id);
            if (form) {
                const title = form instanceof ActionForm ? form.getTitle() : { text: form.getTitle() };
                const iconPath = form.options.iconPath || "";
                selector.button(title, iconPath);
            }
        });
        const response = await selector.show(player);
        if (!response.canceled && response.selection !== undefined) {
            this.showForm(player, formIds[response.selection], false);
        }
    }
    async showForm(player, formId, isMain = false, isInteraction = false) {
        const form = this.actionForms.get(formId) || this.modalForms.get(formId);
        if (!form) {
            return;
        }
        if (isMain) {
            this.navigationStack = [];
        }
        this.navigationStack.push(formId);
        this.currentFormOpenedViaInteraction = isInteraction;
        if (form instanceof ActionForm) {
            const { form: compiledForm, buttonCount, backButtonIndex, } = form.compile(new Map([...this.actionForms, ...this.modalForms]), this.references);
            const response = await compiledForm.show(player);
            if (response.canceled) {
                return;
            }
            if (response.selection === undefined) {
                return;
            }
            if (backButtonIndex !== undefined && response.selection === backButtonIndex) {
                this.handleBackNavigation(player);
                return;
            }
            const referencedForms = this.references.get(formId) || [];
            if (response.selection < referencedForms.length) {
                const selectedReference = referencedForms[response.selection];
                if (this.actionForms.has(selectedReference) || this.modalForms.has(selectedReference)) {
                    this.showForm(player, selectedReference);
                    return;
                }
            }
        }
        else if (form instanceof ModalForm) {
            const compiledForm = form.compile();
            const response = await compiledForm.show(player);
            if (response.canceled) {
                // Handle the case when the form is closed without navigating to another form.
                if (!isInteraction && this.navigationStack.length > 1) {
                    // If the form was not opened via interaction, remove the current form from the stack
                    this.navigationStack.pop();
                }
                // Do nothing else, just return.
                return;
            }
            else if (response.formValues) {
                console.log("ModalForm response:", response.formValues);
                world.sendMessage({ translate: `${namespace}.form.submitted` });
                form.options.controls.forEach((control, index) => {
                    if (control.dynamicProperty && response.formValues) {
                        const value = response.formValues[index];
                        this.setDynamicProperty(control.dynamicProperty, value);
                    }
                });
            }
        }
    }
    handleBackNavigation(player) {
        if (this.currentFormOpenedViaInteraction) {
            const mainFormId = this.getMainFormIdForCurrentForm();
            if (mainFormId) {
                this.showForm(player, mainFormId, true);
            }
        }
        else if (this.navigationStack.length > 1) {
            this.navigationStack.pop();
            const previousPage = this.navigationStack.pop();
            if (previousPage) {
                this.showForm(player, previousPage);
            }
        }
        else {
            // Handle case where there's no previous page in the stack
        }
    }
    getMainFormIdForCurrentForm() {
        const currentFormId = this.navigationStack[this.navigationStack.length - 1];
        for (const [trigger, mainFormId] of this.mainForms) {
            if (this.triggers.get(trigger)?.includes(currentFormId)) {
                return mainFormId;
            }
        }
        return undefined;
    }
    registerForms() {
        forms.forEach(({ forms: formGroup, trigger, mainForm }) => {
            formGroup.forEach((formData) => {
                const isMainForm = formData.id === mainForm;
                let formInstance;
                if (formData instanceof ActionForm) {
                    formInstance = new ActionForm(formData.id, formData.options, isMainForm);
                    this.actionForms.set(formInstance.id, formInstance);
                }
                else if (formData instanceof ModalForm) {
                    formInstance = new ModalForm(formData.id, formData.options, isMainForm);
                    this.modalForms.set(formInstance.id, formInstance);
                }
                else {
                    throw new Error(`Unknown form type for form with id: ${formData.id}`);
                }
                if (isMainForm) {
                    this.mainForms.set(trigger, formInstance.id);
                }
                if (!this.triggers.has(trigger)) {
                    this.triggers.set(trigger, []);
                }
                this.triggers.get(trigger)?.push(formInstance.id);
                if (formData.options.references) {
                    formData.options.references.forEach((refId) => {
                        if (!this.references.has(refId)) {
                            this.references.set(refId, []);
                        }
                        this.references.get(refId)?.push(formInstance.id);
                    });
                }
            });
        });
    }
    setDynamicProperty(identifier, value) {
        try {
            world.setDynamicProperty(identifier, value);
        }
        catch (error) {
            console.warn(`Failed to set dynamic property ${identifier}: ${error}`);
        }
    }
}
