import { world } from "@minecraft/server"
import { ModalFormData, ActionFormData } from "@minecraft/server-ui"



export class XpTankComponent {
    constructor() {
        this.onStepOn = this.onStepOn.bind(this);
        this.onPlayerInteract = this.onPlayerInteract.bind(this);
        // this.onPlace = this.onPlace.bind(this);
        // this.spike_above = false
        this.DYNAMIC_PROPERTY_NAME = "pb_red:xp_tank_data";
    }

    getXpTankData() {
        return JSON.parse(world.getDynamicProperty(this.DYNAMIC_PROPERTY_NAME) || "[]");
    }

    setXpTankData(data) {
        world.setDynamicProperty(this.DYNAMIC_PROPERTY_NAME, JSON.stringify(data));
    }

    updateXpTankData(block, delta) {
        const locationStr = `${block.location.x},${block.location.y},${block.location.z}`;
        let data = this.getXpTankData();
        let tank = data.find(tank => tank.loc === locationStr);

        if (!tank) {
            tank = { loc: locationStr, xpValue: 0 };
            data.push(tank);
        }

        if (tank.xpValue + delta <= 10000) {
            tank.xpValue += delta;
        }

        this.setXpTankData(data);
        this.updateBlockXpLevel(block, tank.xpValue);
    }

    updateBlockXpLevel(block, xpValue) {
        const level = Math.round(xpValue / 1000);
        block.setPermutation(block.permutation.withState('pb_red:xp_level', level));
    }
    removeExperience(player, xpToRemove) {
        let totalXp = player.getTotalXp();

        let newTotalXp = totalXp - xpToRemove;
        if (newTotalXp < 0) {
            newTotalXp = 0;
        }
        let currentXp = totalXp;
        while (currentXp > newTotalXp) {
            let xpForCurrentLevel = player.xpEarnedAtCurrentLevel;
            let totalXpForNextLevel = player.totalXpNeededForNextLevel;
            let xpToRemoveForLevel = Math.min(xpForCurrentLevel, currentXp - newTotalXp);

            player.addExperience(-xpToRemoveForLevel);
            currentXp -= xpToRemoveForLevel;

            if (xpToRemoveForLevel === xpForCurrentLevel && currentXp > newTotalXp) {
                player.addLevels(-1);
                currentXp -= (totalXpForNextLevel - xpForCurrentLevel);
            }
        }
        if (player.getTotalXp() > newTotalXp) {
            player.addExperience(newTotalXp - player.getTotalXp());
        }
    }

    // onPlace(e) {
    //     const block = e.block;
    //     if (block.above().permutation.matches("pb_red:spike") && this.spike_above == false) {
    //         block.dimension.runCommand(`tellraw @p {"rawtext":[{"text":"§bThis Xp Tank is now linked to the Spike above"}]}`)
    //         block.dimension.runCommand(`playsound random.toast @a ${block.location.x} ${block.location.y} ${block.location.z}`)
    //         this.spike_above = true
    //     } else {
    //         this.spike_above = false
    //     }
    // }

    onPlayerInteract(e) {
        const block = e.block;
        const player = e.player;
        const locationStr = `${block.location.x},${block.location.y},${block.location.z}`;
        let data = this.getXpTankData();
        let tank = data.find(tank => tank.loc === locationStr);

        if (player.isSneaking) {
            if (!tank) {
                this.updateXpTankData(block, 1)
            }
            block.dimension.runCommand(`playsound random.click @a ${block.location.x} ${block.location.y} ${block.location.z}`)

            const XpTankMainGUI = new ActionFormData()
            XpTankMainGUI.title("Xp Tank")
            XpTankMainGUI.body("select to withdraw or deposit XP: ")
            XpTankMainGUI.button("Withdraw")
            XpTankMainGUI.button("Deposit")
            XpTankMainGUI.show(player).then((selec) => {
                if (selec.canceled) {
                    return;
                }
                switch (selec.selection) {
                    case 0:
                        try {
                            const XpTankWithdrawGUI = new ModalFormData()
                            XpTankWithdrawGUI.title("Xp Tank")
                            XpTankWithdrawGUI.slider("Xp Amount to withdraw", 0, tank.xpValue, 1, 0)
                            XpTankWithdrawGUI.show(player).then((selec) => {
                                if (selec.canceled) {
                                    return;
                                }
                                let xpChange = selec.formValues[0];
                                player.runCommand(`xp ${xpChange} @s`)
                                player.runCommand(`playsound random.levelup @a ~ ~ ~`)
                                tank.xpValue -= xpChange;
                                this.setXpTankData(data);
                                this.updateBlockXpLevel(block, tank.xpValue);
                            });
                        } catch {
                            //console.warn("error withdraw")
                            player.runCommand(`tellraw @s {"rawtext":[{"text":"§bXp Tank Initialized. §lInteract Again"}]}`)
                        }

                        break;
                    case 1:
                        try {
                            const XpTankDeposeGUI = new ModalFormData()
                            XpTankDeposeGUI.title("Xp Tank")
                            XpTankDeposeGUI.slider("Xp Amount to deposit", 0, Math.min(10000 - tank.xpValue, player.getTotalXp()), 1, 0)
                            XpTankDeposeGUI.show(player).then((selec) => {
                                if (selec.canceled) {
                                    return;
                                }
                                let xpChange = selec.formValues[0];
                                this.removeExperience(player, xpChange)
                                block.dimension.runCommand(`playsound random.potion.brewed @a ${block.location.x} ${block.location.y} ${block.location.z}`)
                                tank.xpValue += xpChange;
                                this.setXpTankData(data);
                                this.updateBlockXpLevel(block, tank.xpValue);
                            });
                        } catch {
                            //console.warn("error deposit")
                            player.runCommand(`tellraw @s {"rawtext":[{"text":"§bXp Tank Initialized. §lInteract Again"}]}`)
                        }
                        break;
                }
            })

            return

        }

        if (tank && tank?.xpValue >= 500) {
            tank.xpValue -= 500;
            this.setXpTankData(data);
            this.updateBlockXpLevel(block, tank.xpValue);
            player.runCommand(`xp 500 @s`)
            player.runCommand(`playsound random.levelup @a ~ ~ ~`)
        } else {
            if (tank)
                player.runCommand(`tellraw @s {"rawtext":[{"text":"§cNot enough xp to collect. (${tank.xpValue}/500)"}]}`)
            else
                player.runCommand(`tellraw @s {"rawtext":[{"text":"§cNot enough xp to collect. (0/500)"}]}`)

        }
    }

    removeDynamicProperties(block) {
        const locationStr = `${block.location.x},${block.location.y},${block.location.z}`;
        let data = this.getXpTankData();
        let tank = data.find(tank => tank.loc === locationStr);
        if (tank) {
            if (tank.xpValue > 25) {
                block.dimension.runCommandAsync(`xp ${tank.xpValue - 25} @p`);
                block.dimension.runCommandAsync(`playsound random.levelup @a ${block.location.x} ${block.location.y} ${block.location.z}`)
                for (let i = 0; i < 10; i++)
                    block.dimension.runCommandAsync(`summon xp_orb ${block.location.x} ${block.location.y} ${block.location.z}`)
            }
            data = data.filter(t => t.loc !== locationStr);
            this.setXpTankData(data);
        }
    }

    onStepOn(e) {
        const block = e.block;

        for (const aboveEntity of block.dimension.getEntitiesAtBlockLocation(block.location)) {
            if (aboveEntity.typeId === 'pb_red:xp_tank_updater_dummy') {
                let entityTag = aboveEntity.getTags().find(item => item.startsWith("pb_red:xp_tank_updater_xp_level:"));
                let xpAmount = parseInt(entityTag.split(":")[2])
                aboveEntity.remove()
                const locationStr = `${block.location.x},${block.location.y},${block.location.z}`;
                let data = this.getXpTankData();
                let tank = data.find(tank => tank.loc === locationStr);
                // console.warn(tank.xpValue)
                if (tank && tank.xpValue >= 10000) {
                    // console.warn("XP tank is full");
                    continue;
                }

                // console.warn("XP orb collected");
                this.updateXpTankData(block, xpAmount);


            }

        }
    }
}