import { system, world, Player, ItemStack, } from "@minecraft/server";
import { ActionFormData } from "@minecraft/server-ui";
import ScriptingModule from "./scriptingModule";
import { AchievementForm, ActionForm, ModalForm, } from "./class/form";
import { forms } from "../config/form/_index"; // Import forms configuration
import { addItemToInventory, removeItemFromInventory, } from "./helper/utils";
import { namespace } from "../config/_config";
const UNLOCKED_FORMS_PROPERTY = `${namespace}:unlockedForms`;
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;
        // Add these arrays at the top of FormModule to store forms by triggers
        this.entityKillForms = [];
        this.blockBreakForms = [];
        this.blockPlaceForms = [];
        this.blockInteractForms = [];
        this.entityInteractForms = [];
        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);
                }
            }
        };
        this.registerForms(); // Register forms immediately upon instantiation
    }
    onInitialize() {
        world.afterEvents.itemUse.subscribe(this.handleItemUse);
        // Check for inventory-based form unlock
        system.runInterval(() => {
            world.getPlayers().forEach((player) => this.triggerFormFromInventory(player));
        }, 20);
        // this.registerForms();
        system.afterEvents.scriptEventReceive.subscribe((event) => {
            if (event.id == `${namespace}:reset_forms`) {
                const properties = world.getDynamicPropertyIds();
                for (const key of properties) {
                    // Check if the property key starts with the namespace hint prefix
                    if (key.startsWith(UNLOCKED_FORMS_PROPERTY)) {
                        world.setDynamicProperty(key, false); // Set the property to false
                    }
                }
            }
        });
        this.registerActionBasedEvents();
    }
    getInteractionForEntity(typeId, itemTypeId) {
        for (const form of this.actionForms.values()) {
            if (form.options.interact?.entities?.includes(typeId)) {
                return form;
            }
        }
        for (const form of this.modalForms.values()) {
            if (form.options.interact?.entities?.includes(typeId)) {
                return form;
            }
        }
        return null;
    }
    getUnlockedForms() {
        const unlockedFormsString = world.getDynamicProperty(UNLOCKED_FORMS_PROPERTY) || "[]";
        return new Set(JSON.parse(unlockedFormsString));
    }
    setUnlockedForms(unlockedForms) {
        world.setDynamicProperty(UNLOCKED_FORMS_PROPERTY, JSON.stringify(Array.from(unlockedForms)));
    }
    checkFormUnlock(player, itemTypeId) {
        for (const form of this.actionForms.values()) {
            const unlock = form.options.unlock;
            if (!unlock)
                continue;
            // Check itemID-based triggers
            const matchesItemID = "itemID" in unlock.trigger && unlock.trigger.itemID === itemTypeId;
            // Check hasItem-based triggers
            const matchesHasItem = unlock.trigger.hasItem && unlock.trigger.hasItem.id === itemTypeId;
            if (matchesItemID || matchesHasItem) {
                const scope = unlock.property === "world" ? "world" : "player";
                let unlockedForms = scope === "world" ? getWorldUnlockedForms() : getPlayerUnlockedForms(player);
                if (!unlockedForms.has(form.id)) {
                    unlockedForms.add(form.id);
                    if (scope === "world") {
                        setWorldUnlockedForms(unlockedForms);
                    }
                    else {
                        setPlayerUnlockedForms(player, unlockedForms);
                    }
                    // Play sound if defined
                    if (unlock.sound) {
                        player.playSound(unlock.sound);
                    }
                    // Messages
                    if (unlock.messages) {
                        unlock.messages.forEach((message) => {
                            if (message.target === "chat") {
                                if (message.private) {
                                    player.sendMessage({ translate: message.text });
                                }
                                else {
                                    world.sendMessage({ translate: message.text });
                                }
                            }
                            else if (message.target === "actionbar") {
                                if (message.private) {
                                    player.onScreenDisplay.setActionBar({ translate: message.text });
                                }
                                else {
                                    for (const p of world.getAllPlayers()) {
                                        p.onScreenDisplay.setActionBar({ translate: message.text });
                                    }
                                }
                            }
                            else if (message.target === "title") {
                                if (message.private) {
                                    player.onScreenDisplay.setTitle({ translate: message.text });
                                }
                                else {
                                    for (const p of world.getAllPlayers()) {
                                        p.onScreenDisplay.setTitle({ translate: message.text });
                                    }
                                }
                            }
                        });
                    }
                    // Handle item removal if hasItem.removeItem is true (default true)
                    const removeItem = unlock.trigger.hasItem?.removeItem !== false;
                    if (removeItem) {
                        removeItemFromInventory(player, itemTypeId);
                    }
                    // Handle rewards
                    const reward = unlock.reward;
                    if (scope === "world") {
                        setWorldUnlockedForms(unlockedForms);
                        const allPlayers = world.getAllPlayers();
                        if (reward) {
                            if (typeof reward.xp === "number" && reward.xp > 0) {
                                for (const p of allPlayers) {
                                    p.addLevels(reward.xp);
                                }
                            }
                            if (reward.items && Array.isArray(reward.items)) {
                                for (const p of allPlayers) {
                                    for (const rewardedItem of reward.items) {
                                        addItemToInventory(p, new ItemStack(rewardedItem.id, rewardedItem.count));
                                    }
                                }
                            }
                        }
                    }
                    else {
                        if (reward) {
                            if (typeof reward.xp === "number" && reward.xp > 0) {
                                player.addLevels(reward.xp);
                            }
                            if (reward.items && Array.isArray(reward.items)) {
                                for (const rewardedItem of reward.items) {
                                    addItemToInventory(player, new ItemStack(rewardedItem.id, rewardedItem.count));
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    triggerFormFromInventory(player) {
        const unlockedForms = this.getUnlockedForms();
        // Iterate over action forms that have `lookInInventory` set to true
        this.actionForms.forEach((form) => {
            const unlock = form.options.unlock;
            if (unlock?.trigger.hasItem) {
                // Check if the player has the item in their inventory
                const inventory = player.getComponent("inventory");
                const container = inventory.container;
                for (let i = 0; i < container.size; i++) {
                    const item = container.getItem(i);
                    if (item && item.typeId === unlock.trigger.hasItem?.id) {
                        this.checkFormUnlock(player, unlock.trigger.hasItem?.id); // Trigger the form unlock logic
                        break;
                    }
                }
            }
        });
    }
    getInteractionForBlock(typeId, itemTypeId) {
        for (const form of this.actionForms.values()) {
            if (form.options.interact?.blocks?.includes(typeId)) {
                return form;
            }
        }
        for (const form of this.modalForms.values()) {
            if (form.options.interact?.blocks?.includes(typeId)) {
                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;
        // Determine which unlockedForms set to use
        const unlockProperty = form.options.unlock?.property === "world" ? "world" : "player";
        const unlockedForms = unlockProperty === "world" ? getWorldUnlockedForms() : getPlayerUnlockedForms(player);
        if (form instanceof ActionForm) {
            // Note the added 'player' argument here
            const { form: compiledForm, buttonCount, backButtonIndex, } = form.compile(player, new Map([...this.actionForms, ...this.modalForms]), this.references, unlockedForms);
            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) {
                const referencedForms = form.options.references || [];
                if (referencedForms.length > 0) {
                    this.showForm(player, referencedForms[0]);
                }
                return;
            }
            else if (response.formValues) {
                console.log("ModalForm response:", response.formValues);
                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 AchievementForm) {
                    formInstance = formData;
                    this.actionForms.set(formInstance.id, formInstance);
                }
                else if (formData instanceof ActionForm) {
                    formInstance = formData;
                    this.actionForms.set(formInstance.id, formInstance);
                }
                else if (formData instanceof ModalForm) {
                    formInstance = formData;
                    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);
                    });
                }
                // Now check for action-based triggers
                if (formInstance instanceof ActionForm && formInstance.options.unlock) {
                    const unlock = formInstance.options.unlock;
                    if (unlock.trigger) {
                        // If these triggers are always arrays, handle them as arrays
                        if (Array.isArray(unlock.trigger.entityKill)) {
                            this.entityKillForms.push({
                                form: formInstance,
                                entityTypes: unlock.trigger.entityKill,
                            });
                        }
                        if (Array.isArray(unlock.trigger.blockDestroy)) {
                            this.blockBreakForms.push({
                                form: formInstance,
                                blockTypes: unlock.trigger.blockDestroy,
                            });
                        }
                        if (Array.isArray(unlock.trigger.blockPlace)) {
                            this.blockPlaceForms.push({
                                form: formInstance,
                                blockTypes: unlock.trigger.blockPlace,
                            });
                        }
                        if (Array.isArray(unlock.trigger.blockInteract)) {
                            this.blockInteractForms.push({
                                form: formInstance,
                                blockTypes: unlock.trigger.blockInteract,
                            });
                        }
                        if (Array.isArray(unlock.trigger.entityInteract)) {
                            this.entityInteractForms.push({
                                form: formInstance,
                                entityTypes: unlock.trigger.entityInteract,
                            });
                        }
                    }
                }
            });
        });
    }
    registerActionBasedEvents() {
        // entityKill trigger
        world.afterEvents.entityDie.subscribe((event) => {
            if (this.entityKillForms.length > 0) {
                const damager = event.damageSource.damagingEntity;
                if (damager instanceof Player) {
                    const deadEntityType = event.deadEntity.typeId;
                    for (const { form, entityTypes } of this.entityKillForms) {
                        if (entityTypes.includes(deadEntityType)) {
                            this.unlockFormForTrigger(form, damager);
                        }
                    }
                }
            }
        });
        // blockBreak trigger
        world.afterEvents.playerBreakBlock.subscribe((event) => {
            if (this.blockBreakForms.length > 0) {
                const player = event.player;
                const brokenBlockType = event.brokenBlockPermutation.type.id;
                for (const { form, blockTypes } of this.blockBreakForms) {
                    if (blockTypes.includes(brokenBlockType)) {
                        this.unlockFormForTrigger(form, player);
                    }
                }
            }
        });
        // blockPlace trigger
        world.afterEvents.playerPlaceBlock.subscribe((event) => {
            if (this.blockPlaceForms.length > 0) {
                const player = event.player;
                const placedBlockType = event.block.typeId;
                for (const { form, blockTypes } of this.blockBreakForms) {
                    if (blockTypes.includes(placedBlockType)) {
                        this.unlockFormForTrigger(form, player);
                    }
                }
            }
        });
        // blockInteract trigger
        world.afterEvents.playerInteractWithBlock.subscribe((event) => {
            if (this.blockInteractForms.length > 0) {
                const player = event.player;
                const interactedBlockType = event.block.typeId;
                for (const { form, blockTypes } of this.blockInteractForms) {
                    if (blockTypes.includes(interactedBlockType)) {
                        this.unlockFormForTrigger(form, player);
                    }
                }
            }
        });
        // entityInteract trigger (assuming a playerInteractWithEntity event exists)
        world.afterEvents.playerInteractWithEntity.subscribe((event) => {
            if (this.entityInteractForms.length > 0) {
                const player = event.player;
                const interactedEntityType = event.target.typeId;
                for (const { form, entityTypes } of this.entityInteractForms) {
                    if (entityTypes.includes(interactedEntityType)) {
                        this.unlockFormForTrigger(form, player);
                    }
                }
            }
        });
    }
    setDynamicProperty(identifier, value) {
        try {
            world.setDynamicProperty(identifier, value);
        }
        catch (error) {
            console.warn(`Failed to set dynamic property ${identifier}: ${error}`);
        }
    }
    /**
     * Unlocks the given form for the given player based on a trigger (non-item).
     */
    unlockFormForTrigger(form, player) {
        const unlock = form.options.unlock;
        if (!unlock)
            return;
        const scope = unlock.property === "world" ? "world" : "player";
        let unlockedForms = scope === "world" ? getWorldUnlockedForms() : getPlayerUnlockedForms(player);
        if (!unlockedForms.has(form.id)) {
            unlockedForms.add(form.id);
            if (scope === "world") {
                setWorldUnlockedForms(unlockedForms);
            }
            else {
                setPlayerUnlockedForms(player, unlockedForms);
            }
            // Play sound if defined
            if (unlock.sound) {
                player.playSound(unlock.sound);
            }
            if (unlock.messages) {
                unlock.messages.forEach((message) => {
                    if (message.target === "chat") {
                        if (message.private) {
                            player.sendMessage({ translate: message.text, with: [player.name] });
                        }
                        else {
                            world.sendMessage({ translate: message.text, with: [player.name] });
                        }
                    }
                    if (message.target === "actionbar") {
                        if (message.private) {
                            player.onScreenDisplay.setActionBar({ translate: message.text, with: [player.name] });
                        }
                        else {
                            world.getAllPlayers().forEach((p) => {
                                p.onScreenDisplay.setActionBar({ translate: message.text, with: [player.name] });
                            });
                        }
                    }
                    if (message.target === "title") {
                        if (message.private) {
                            player.onScreenDisplay.setTitle({ translate: message.text, with: [player.name] });
                        }
                        else {
                            world.getAllPlayers().forEach((p) => {
                                p.onScreenDisplay.setTitle({ translate: message.text, with: [player.name] });
                            });
                        }
                    }
                });
            }
            // Handle rewards
            const reward = unlock.reward;
            if (scope === "world") {
                setWorldUnlockedForms(unlockedForms);
                const allPlayers = world.getAllPlayers();
                if (reward) {
                    if (typeof reward.xp === "number" && reward.xp > 0) {
                        for (const p of allPlayers) {
                            p.addLevels(reward.xp);
                        }
                    }
                    if (reward.items && Array.isArray(reward.items)) {
                        for (const p of allPlayers) {
                            for (const rewardedItem of reward.items) {
                                addItemToInventory(p, new ItemStack(rewardedItem.id, rewardedItem.count));
                            }
                        }
                    }
                }
            }
            else {
                if (reward) {
                    if (typeof reward.xp === "number" && reward.xp > 0) {
                        player.addLevels(reward.xp);
                    }
                    if (reward.items && Array.isArray(reward.items)) {
                        for (const rewardedItem of reward.items) {
                            addItemToInventory(player, new ItemStack(rewardedItem.id, rewardedItem.count));
                        }
                    }
                }
            }
        }
    }
}
export function getWorldUnlockedForms() {
    const unlockedFormsString = world.getDynamicProperty(`${namespace}:unlockedForms`) || "[]";
    return new Set(JSON.parse(unlockedFormsString));
}
export function setWorldUnlockedForms(unlockedForms) {
    world.setDynamicProperty(`${namespace}:unlockedForms`, JSON.stringify(Array.from(unlockedForms)));
}
export function getPlayerUnlockedForms(player) {
    const propertyId = `${namespace}:unlockedForms`;
    const unlockedFormsString = player.getDynamicProperty(propertyId) || "[]";
    return new Set(JSON.parse(unlockedFormsString));
}
export function setPlayerUnlockedForms(player, unlockedForms) {
    const propertyId = `${namespace}:unlockedForms`;
    player.setDynamicProperty(propertyId, JSON.stringify(Array.from(unlockedForms)));
}
export const form = new FormModule();
