import { EntityDamageCause, EquipmentSlot, world } from "@minecraft/server";
import { ActionFormData } from "@minecraft/server-ui";
export const MAX_LIMB_HEALTH = 100;
export var Limb;
(function (Limb) {
    Limb["Head"] = "Head";
    Limb["Body"] = "Body";
    Limb["RightArm"] = "RightArm";
    Limb["LeftArm"] = "LeftArm";
    Limb["Legs"] = "Legs";
})(Limb || (Limb = {}));
// const LIMB_HEALTHS = { // Not used, maybe in the future
//     [Limb.Head]: MAX_LIMB_HEALTH,
//     [Limb.Body]: MAX_LIMB_HEALTH * 2,
//     [Limb.LeftArm]: MAX_LIMB_HEALTH,
//     [Limb.RightArm]: MAX_LIMB_HEALTH,
//     [Limb.Legs]: MAX_LIMB_HEALTH * 2
// }
const LimbFormMappings = {
    100: {
        color: "§2",
        stage: 0
    },
    75: {
        color: "§p",
        stage: 1
    },
    50: {
        color: "§n",
        stage: 2
    },
    25: {
        color: "§n", // Same stage as before, I just had to round to 25
        stage: 2
    },
    0: {
        color: "§c",
        stage: 3
    }
};
export const LimbDamagedThreshold = {
    [Limb.Head]: MAX_LIMB_HEALTH / 4,
    [Limb.Body]: -1, // -1 should be so it's never shown
    [Limb.LeftArm]: -1,
    [Limb.RightArm]: MAX_LIMB_HEALTH / 2,
    [Limb.Legs]: MAX_LIMB_HEALTH / 2
};
const LimbDamageSources = {
    [EntityDamageCause.entityAttack]: {
        Head: [0, 2],
        Body: [1, 3],
        LeftArm: [0, 1],
        RightArm: [0, 1],
        Legs: [0, 1],
    },
    [EntityDamageCause.fall]: {
        Head: [0, 0],
        Body: [0, 0],
        LeftArm: [0, 0],
        RightArm: [0, 0],
        Legs: [1, 2],
    },
    [EntityDamageCause.magma]: {
        Head: [0, 0],
        Body: [0, 0],
        LeftArm: [0, 0],
        RightArm: [0, 0],
        Legs: [1, 2],
    },
    [EntityDamageCause.anvil]: {
        Head: [3, 3],
        Body: [0, 0],
        LeftArm: [0, 0],
        RightArm: [0, 0],
        Legs: [0, 0],
    },
    [EntityDamageCause.fallingBlock]: {
        Head: [3, 3],
        Body: [0, 0],
        LeftArm: [0, 0],
        RightArm: [0, 0],
        Legs: [0, 0],
    },
    [EntityDamageCause.magic]: {
        Head: [1, 3],
        Body: [1, 3],
        LeftArm: [0, 0],
        RightArm: [0, 0],
        Legs: [0, 0],
    },
    [EntityDamageCause.wither]: {
        Head: [1, 3],
        Body: [1, 3],
        LeftArm: [0, 0],
        RightArm: [0, 0],
        Legs: [0, 0],
    },
    [EntityDamageCause.freezing]: {
        Head: [0, 1],
        Body: [0, 1],
        LeftArm: [1, 1],
        RightArm: [1, 1],
        Legs: [1, 1],
    },
    [EntityDamageCause.blockExplosion]: {
        Head: [1, 3],
        Body: [1, 3],
        LeftArm: [1, 3],
        RightArm: [1, 3],
        Legs: [1, 3],
    },
    [EntityDamageCause.entityExplosion]: {
        Head: [1, 3],
        Body: [1, 3],
        LeftArm: [1, 3],
        RightArm: [1, 3],
        Legs: [1, 3],
    },
    [EntityDamageCause.drowning]: {
        Head: [1, 3],
        Body: [1, 2],
        LeftArm: [0, 0],
        RightArm: [0, 0],
        Legs: [0, 0],
    },
    [EntityDamageCause.suffocation]: {
        Head: [1, 3],
        Body: [1, 2],
        LeftArm: [0, 0],
        RightArm: [0, 0],
        Legs: [0, 0],
    },
    [EntityDamageCause.fire]: {
        Head: [1, 2],
        Body: [1, 2],
        LeftArm: [1, 2],
        RightArm: [1, 2],
        Legs: [1, 2],
    },
    [EntityDamageCause.fireTick]: {
        Head: [1, 2],
        Body: [1, 2],
        LeftArm: [1, 2],
        RightArm: [1, 2],
        Legs: [1, 2],
    },
    [EntityDamageCause.lava]: {
        Head: [2, 3],
        Body: [2, 3],
        LeftArm: [2, 3],
        RightArm: [2, 3],
        Legs: [2, 3],
    },
    [EntityDamageCause.selfDestruct]: {
        Head: [0, 0],
        Body: [0, 0],
        LeftArm: [0, 0],
        RightArm: [0, 0],
        Legs: [0, 0],
    },
    [EntityDamageCause.starve]: {
        Head: [0, 0],
        Body: [0, 0],
        LeftArm: [0, 0],
        RightArm: [0, 0],
        Legs: [0, 0],
    },
    [EntityDamageCause.none]: {
        Head: [0, 0],
        Body: [0, 0],
        LeftArm: [0, 0],
        RightArm: [0, 0],
        Legs: [0, 0],
    },
    [EntityDamageCause.override]: {
        Head: [0, 0],
        Body: [0, 0],
        LeftArm: [0, 0],
        RightArm: [0, 0],
        Legs: [0, 0],
    },
    [EntityDamageCause.campfire]: {
        Head: [0, 0],
        Body: [0, 0],
        LeftArm: [0, 0],
        RightArm: [0, 0],
        Legs: [1, 2],
    },
    [EntityDamageCause.soulCampfire]: {
        Head: [0, 0],
        Body: [0, 0],
        LeftArm: [0, 0],
        RightArm: [0, 0],
        Legs: [1, 2],
    },
    default: {
        Head: [1, 1],
        Body: [1, 1],
        LeftArm: [1, 1],
        RightArm: [1, 1],
        Legs: [1, 1],
    }
};
export const LimbDamageMethods = {
    damageLimb: function (damage, damageType) {
        const limbDamage = LimbDamageSources[damageType] ?? LimbDamageSources.default;
        const getDamage = (dmg, min, max) => { return Math.round((Math.random() * (max - min) + min) * dmg); };
        for (const limb in limbDamage) {
            const min = limbDamage[limb][0];
            const max = limbDamage[limb][1];
            let damageToLimb = getDamage(damage, min, max);
            // Difficulty modifiers
            const difficulty = world.getDynamicProperty('oct_db:worldSetting');
            if (difficulty === 1)
                damageToLimb *= 0.5;
            if (difficulty === 2)
                damageToLimb *= 0.75;
            // FIXME: temporary placeholder for doubling leg and body hp
            if (limb === "Legs" || limb === "Body")
                Math.round(damageToLimb /= 2);
            // Deal limb damage
            const propertyName = `oct_db:${limb}_health`;
            const currentLimbHealth = this.getDynamicProperty(propertyName) ?? 0;
            this.setLimbHealth(limb, currentLimbHealth - damageToLimb);
            // Debug
            // console.warn(`${limb}, damage: ${damageToLimb}. Current health: ${currentLimbHealth}`);
        }
    },
    setLimbHealth: function (limb, health) {
        const setHealth = Math.min(MAX_LIMB_HEALTH, Math.max(0, health));
        const propertyName = `oct_db:${limb}_health`;
        this.setDynamicProperty(propertyName, setHealth);
        // Play animation
        this.playAnimation(`animation.oct_db.health_menu.limb_${limb.toLowerCase()}_${(setHealth / MAX_LIMB_HEALTH * 100).toFixed(0)}`, { controller: `oct:${limb}` });
    },
    refreshLimbHealth: function () {
        for (const limb in Limb) {
            const property = this.getDynamicProperty(`oct_db:${limb}_health`) ?? 999;
            this.setLimbHealth(limb, property);
        }
    },
    resetLimbHealth: function () {
        for (const limb in Limb) {
            this.setLimbHealth(limb, 999);
        }
    },
    getLimbHealth: function (limb) {
        return this.getDynamicProperty(`oct_db:${limb}_health`) ?? 999;
    },
    damageSpecificLimb: function (limb, damage) {
        // Deal limb damage
        const propertyName = `oct_db:${limb}_health`;
        const currentLimbHealth = this.getDynamicProperty(propertyName) ?? 0;
        this.setLimbHealth(limb, currentLimbHealth - damage);
    },
    checkLimbHealth: function () {
        const extraEffectLength = 60;
        const damagedLimbDebuffs = {
            Head: [
                [
                // Nothing
                ],
                [
                    () => this.addEffect("minecraft:darkness", extraEffectLength, { amplifier: 1 })
                ],
                [
                    () => this.addEffect("minecraft:blindness", extraEffectLength, { amplifier: 1 }),
                    () => this.applyTickDamage(),
                ],
            ],
            Body: [
                [
                // Nothing
                ],
                [
                // Nothing
                ],
                [
                    () => this.applyTickDamage(),
                ],
            ],
            RightArm: [
                [
                    () => this.addEffect("minecraft:mining_fatigue", extraEffectLength, { amplifier: 0 })
                ],
                [
                    () => this.addEffect("minecraft:mining_fatigue", extraEffectLength, { amplifier: 1 })
                ],
                [
                // Nothing //FIXME: damage when you punch
                ],
            ],
            LeftArm: [
                [
                // Nothing
                ],
                [
                // Nothing
                ],
                [
                    () => {
                        const equippableComp = this.getComponent("minecraft:equippable");
                        if (!equippableComp.getEquipment(EquipmentSlot.Offhand))
                            return;
                        // Don't drop health monitor
                        if (equippableComp.getEquipment(EquipmentSlot.Offhand).typeId.startsWith("oct_db:health_monitor"))
                            return;
                        const offHandItem = equippableComp.getEquipment(EquipmentSlot.Offhand);
                        this.dimension.spawnItem(offHandItem, this.location);
                        equippableComp.setEquipment(EquipmentSlot.Offhand, undefined);
                    }
                ],
            ],
            Legs: [
                [
                    () => this.addEffect("minecraft:slowness", extraEffectLength, { amplifier: 0 })
                ],
                [
                    () => this.addEffect("minecraft:slowness", extraEffectLength, { amplifier: 1 })
                ],
                [
                    () => this.addEffect("minecraft:slowness", extraEffectLength, { amplifier: 2 })
                ],
            ],
        };
        for (const limb in Limb) {
            const health = this.getDynamicProperty(`oct_db:${limb}_health`) ?? MAX_LIMB_HEALTH;
            if (health > MAX_LIMB_HEALTH / 2)
                continue;
            {
                const debuffs = damagedLimbDebuffs[limb][0];
                for (const debuff of debuffs) {
                    debuff();
                }
            }
            if (health > MAX_LIMB_HEALTH / 4)
                continue;
            {
                const debuffs = damagedLimbDebuffs[limb][1];
                for (const debuff of debuffs) {
                    debuff();
                }
            }
            if (health >= MAX_LIMB_HEALTH / MAX_LIMB_HEALTH)
                continue;
            {
                const debuffs = damagedLimbDebuffs[limb][2];
                for (const debuff of debuffs) {
                    debuff();
                }
            }
        }
    },
    useBandage: function (isEnhanced) {
        const limbArr = Object.values(Limb);
        const bandageForm = new ActionFormData();
        bandageForm.title({ rawtext: [{ translate: "forms.bandage.title" }] });
        bandageForm.body({ rawtext: [{ translate: `forms.bandage.body.${isEnhanced ? "enhanced" : "normal"}` }] });
        for (const limb of limbArr) {
            const limbHealth = this.getDynamicProperty(`oct_db:${limb}_health`) ?? 999;
            const limbHealthPercent = Math.round((limbHealth / MAX_LIMB_HEALTH) * 100);
            const limbHealthPercentRounded = Math.min(100, Math.max(0, Math.floor((limbHealthPercent - 1) / 25) * 25 + 25));
            const color = LimbFormMappings[limbHealthPercentRounded].color;
            const stage = LimbFormMappings[limbHealthPercentRounded].stage;
            bandageForm.button({
                rawtext: [
                    {
                        translate: `forms.button.bandage.${limb}`, with: [
                            `${color}`,
                            `${limbHealthPercent}`
                        ]
                    }
                ]
            }, `textures/octovon/db/menu/limbs/${limb}_st${stage}`);
        }
        bandageForm.show(this).then(result => {
            if (result.canceled)
                return;
            const limb = limbArr[result.selection];
            const setHealth = (this.getDynamicProperty(`oct_db:${limb}_health`) ?? 999) + (isEnhanced ? MAX_LIMB_HEALTH : (MAX_LIMB_HEALTH / 2));
            this.setLimbHealth(limb, setHealth);
            // Consume bandage
            const equippableComp = this.getComponent("minecraft:equippable");
            const bandageItem = equippableComp.getEquipment(EquipmentSlot.Mainhand);
            if (bandageItem) { // Checking just in case, this should never be false
                const newItem = bandageItem.clone();
                if (newItem.amount === 1) {
                    equippableComp.setEquipment(EquipmentSlot.Mainhand, undefined);
                }
                else {
                    newItem.amount -= 1;
                    equippableComp.setEquipment(EquipmentSlot.Mainhand, newItem);
                }
            }
            // VFX
            this.dimension.spawnParticle("oct_db:healing.root", this.location);
            this.playSound(`chime.amethyst_block`, { pitch: 1.5 });
        });
    },
    checkBreakBlockDamage: function (result) {
        const rightArmDamage = 1; // How much to damage the right arm
        // Broken block data
        const brokenBlockPerm = result.brokenBlockPermutation;
        const blockTags = brokenBlockPerm.getTags();
        // Held item data
        const heldItem = result.itemStackBeforeBreak;
        const heldItemTags = heldItem?.getTags() ?? [];
        // If pickaxe or axe should've been used
        if ((blockTags.includes("minecraft:is_pickaxe_item_destructible") && !heldItemTags.includes("minecraft:is_pickaxe")) ||
            (blockTags.includes("minecraft:is_axe_item_destructible") && !heldItemTags.includes("minecraft:is_axe"))) {
            this.damageSpecificLimb(Limb.RightArm, rightArmDamage);
            // console.warn(`Damage limb`)
        }
    },
};
export function initBreakBlockDamage() {
    world.afterEvents.playerBreakBlock.subscribe(result => {
        result.player.checkBreakBlockDamage(result);
    });
}
