// ================= NBT-AWARE WOOD STYLE SCRIPT =================
// Synchronizes with Narutomod's JutsuCDMap AND CustomNPCs stored data
// ================= CONFIG =================
var BASE_COOLDOWN = 30;           // Balanced casting speed
var BURIAL_COOLDOWN = 100;        // Specific cooldown for WOOD_BURIAL
var WINDUP_TICKS = 15;
var AGGRESSIVE_HP_RATIO = 0.3;
var SPIKE_BURST_COUNT = 3;
var SPIKE_BURST_DELAY = 2;

var WEIGHTS_BASE = {
    WOOD_BURIAL: 30,
    ARMATTACK: 45,
    SPIKE: 65
};
var WEIGHTS_AGGRESSIVE = {
    WOOD_BURIAL: 25,
    ARMATTACK: 40,
    SPIKE: 90
};

// ================= MINIMAL SAYINGS =================
var SAYINGS = {
    WOOD_BURIAL: ["Wood Style..."],
    ARMATTACK: ["Wood Arm..."],
    SPIKE: ["Pierce!"]
};

// ================= IMPORTS =================
var ItemMokuton = Java.type("net.narutomod.item.ItemMokuton");
var ItemStack = Java.type("net.minecraft.item.ItemStack");
var NBTTagCompound = Java.type("net.minecraft.nbt.NBTTagCompound");
var NBTTagList = Java.type("net.minecraft.nbt.NBTTagList");

// ================= NBT COOLDOWN HELPERS =================
function getItemNBT(npc) {
    try {
        var me = npc.getMCEntity();
        var inventory = me.getHeldItemMainhand();
        if (!inventory.isEmpty() && inventory.hasTagCompound()) {
            return inventory.getTagCompound();
        }
    } catch (e) {}
    return null;
}

function getJutsuCooldownFromItem(npc, jutsuIndex) {
    // JutsuCDMapKey0 to JutsuCDMapKey6 are in the item's NBT
    try {
        var tag = getItemNBT(npc);
        if (tag && tag.hasKey("JutsuCDMapKey" + jutsuIndex)) {
            var cooldownLong = tag.getLong("JutsuCDMapKey" + jutsuIndex);
            // Convert from long (epoch time) to ticks remaining
            var currentTime = java.lang.System.currentTimeMillis();
            var remainingTime = cooldownLong - currentTime;
            if (remainingTime > 0) {
                return Math.floor(remainingTime / 50); // Convert ms to ticks (20 ticks/second)
            }
        }
    } catch (e) {}
    return 0;
}

function setJutsuCooldownInItem(npc, jutsuIndex, cooldownTicks) {
    // Set cooldown in the item's NBT
    try {
        var tag = getItemNBT(npc);
        if (tag) {
            var cooldownMs = cooldownTicks * 50; // Convert ticks to ms
            var cooldownTime = java.lang.System.currentTimeMillis() + cooldownMs;
            tag.setLong("JutsuCDMapKey" + jutsuIndex, cooldownTime);
            return true;
        }
    } catch (e) {}
    return false;
}

// Map jutsu names to their index in the item's JutsuCDMap
var JUTSU_INDICES = {
    "WOOD_BURIAL": 0,  // Based on ItemMokuton.JutsuEnum order
    "ARMATTACK": 4,
    "SPIKE": 5
};

function getJutsuCooldown(npc, jutsuName) {
    var index = JUTSU_INDICES[jutsuName];
    if (index !== undefined) {
        return getJutsuCooldownFromItem(npc, index);
    }
    return 0;
}

function setJutsuCooldown(npc, jutsuName, cooldownTicks) {
    var index = JUTSU_INDICES[jutsuName];
    if (index !== undefined) {
        return setJutsuCooldownInItem(npc, index, cooldownTicks);
    }
    return false;
}

function canCastJutsu(npc, jutsuName) {
    return getJutsuCooldown(npc, jutsuName) <= 0;
}

// ================= SCRIPT STORAGE HELPERS =================
function getStored(npc, key, defaultVal) {
    var d = npc.getStoreddata();
    if (!d.has(key)) {
        if (defaultVal !== undefined) d.put(key, defaultVal);
        return defaultVal;
    }
    return d.get(key);
}

function setStored(npc, key, val) {
    npc.getStoreddata().put(key, val);
}

function weightedPick(weightObj) {
    var keys = [];
    var sum = 0;
    for (var k in weightObj) { 
        keys.push(k); 
        sum += weightObj[k]; 
    }
    if (sum <= 0) return keys[0];
    var r = Math.random() * sum;
    var acc = 0;
    for (var i = 0; i < keys.length; i++) {
        acc += weightObj[keys[i]];
        if (r <= acc) return keys[i];
    }
    return keys[keys.length-1];
}

function distToTarget(npc, target) {
    if (!target) return 9999;
    var e = npc.getMCEntity();
    var dx = e.posX - target.posX;
    var dy = e.posY - target.posY;
    var dz = e.posZ - target.posZ;
    return Math.sqrt(dx*dx + dy*dy + dz*dz);
}

// ================= JUTSU EXECUTION =================
function executeJutsu(npc, jutsuName, target) {
    var me = npc.getMCEntity();
    var stack = new ItemStack(ItemMokuton.block);
    var performed = false;
    
    // Check if allowed by mod's cooldown system
    if (!canCastJutsu(npc, jutsuName)) {
        return false;
    }
    
    var jutsuEnum = null;
    var cooldownTicks = BASE_COOLDOWN;
    
    if (jutsuName === "WOOD_BURIAL") {
        jutsuEnum = ItemMokuton.WOODBURIAL;
        cooldownTicks = BURIAL_COOLDOWN;
        // 20% chance to speak
        if (Math.random() < 0.2) {
            try { npc.say(SAYINGS.WOOD_BURIAL[0]); } catch(e) {}
        }
    } else if (jutsuName === "ARMATTACK") {
        jutsuEnum = ItemMokuton.ARMATTACK;
        cooldownTicks = Math.floor(BASE_COOLDOWN * 1.2);
        if (Math.random() < 0.2) {
            try { npc.say(SAYINGS.ARMATTACK[0]); } catch(e) {}
        }
    } else if (jutsuName === "SPIKE") {
        jutsuEnum = ItemMokuton.SPIKE;
        cooldownTicks = Math.floor(BASE_COOLDOWN * 0.8);
        if (Math.random() < 0.2) {
            try { npc.say(SAYINGS.SPIKE[0]); } catch(e) {}
        }
    }
    
    if (!jutsuEnum) return false;
    
    try {
        performed = jutsuEnum.jutsu.createJutsu(stack, me, 1.0);
        
        if (performed) {
            // Set cooldown in BOTH systems
            setJutsuCooldown(npc, jutsuName, cooldownTicks);
            
            // Also store in script's data for reference
            if (jutsuName === "WOOD_BURIAL") {
                setStored(npc, "burial_cd", cooldownTicks);
            }
            setStored(npc, "mok_cd", Math.min(cooldownTicks, 20)); // Script's short cooldown
        }
    } catch (err) {
        performed = false;
    }
    
    return performed;
}

// ================= SPIKE BURST HANDLER =================
function handleSpikeBurst(npc) {
    var burstActive = getStored(npc, "spike_burst", 0);
    var spikeCount = getStored(npc, "spike_count", 0);
    var spikeDelay = getStored(npc, "spike_delay", 0);
    
    if (burstActive === 1) {
        if (spikeDelay > 0) {
            spikeDelay--;
            setStored(npc, "spike_delay", spikeDelay);
            return false;
        }
        
        // Fire single spike
        var me = npc.getMCEntity();
        var stack = new ItemStack(ItemMokuton.block);
        
        try {
            ItemMokuton.SPIKE.jutsu.createJutsu(stack, me, 0.8); // Reduced power for burst
        } catch(e) {}
        
        spikeCount++;
        setStored(npc, "spike_count", spikeCount);
        
        if (spikeCount >= SPIKE_BURST_COUNT) {
            // Burst complete - set cooldowns
            var cooldown = Math.floor(BASE_COOLDOWN * 0.9);
            setJutsuCooldown(npc, "SPIKE", cooldown);
            setStored(npc, "mok_cd", 15);
            
            setStored(npc, "spike_burst", 0);
            setStored(npc, "spike_count", 0);
            return true;
        } else {
            // Small delay between spikes
            setStored(npc, "spike_delay", SPIKE_BURST_DELAY);
            return false;
        }
    }
    return false;
}

// ================= MAIN TICK FUNCTION =================
function tick(event) {
    var npc = event.npc;
    if (!npc) return;
    
    // Get entity
    var me;
    try { me = npc.getMCEntity(); } catch(err) { return; }
    
    // ================= TARGET ACQUISITION =================
    var target = npc.getAttackTarget();
    if (!target) {
        var nearby = npc.getWorld().getAllEntities(20);
        for (var i = 0; i < nearby.length; i++) {
            try {
                var entity = nearby[i];
                if (entity.isPlayer && entity.isPlayer()) {
                    target = entity.getMCEntity();
                    npc.setAttackTarget(target);
                    break;
                }
            } catch(e) {}
        }
    }
    
    if (!target) {
        // Reset burst state when no target
        setStored(npc, "spike_burst", 0);
        setStored(npc, "spike_count", 0);
        setStored(npc, "spike_delay", 0);
        return;
    }
    
    // ================= HANDLE SPIKE BURST =================
    var inBurst = handleSpikeBurst(npc);
    if (inBurst || getStored(npc, "spike_burst", 0) === 1) {
        return;
    }
    
    // ================= INITIALIZE STORAGE =================
    if (!npc.getStoreddata().has("mok_cd")) setStored(npc, "mok_cd", 0);
    if (!npc.getStoreddata().has("mok_wind")) setStored(npc, "mok_wind", 0);
    if (!npc.getStoreddata().has("mok_casting")) setStored(npc, "mok_casting", "");
    if (!npc.getStoreddata().has("mok_phase")) setStored(npc, "mok_phase", 0);
    if (!npc.getStoreddata().has("burial_cd")) setStored(npc, "burial_cd", 0);
    
    // ================= UPDATE COMBAT PHASE =================
    try {
        var hp = me.getHealth();
        var maxHp = me.getMaxHealth();
        var ratio = hp / maxHp;
        setStored(npc, "mok_phase", ratio <= AGGRESSIVE_HP_RATIO ? 1 : 0);
    } catch(e) {
        setStored(npc, "mok_phase", 0);
    }
    
    // ================= CHECK COOLDOWNS =================
    var scriptCD = getStored(npc, "mok_cd", 0);
    if (scriptCD > 0) {
        setStored(npc, "mok_cd", scriptCD - 1);
        return;
    }
    
    var burialCD = getStored(npc, "burial_cd", 0);
    if (burialCD > 0) {
        setStored(npc, "burial_cd", burialCD - 1);
    }
    
    // Also check mod's cooldown for WOOD_BURIAL specifically
    if (getJutsuCooldown(npc, "WOOD_BURIAL") > 0) {
        setStored(npc, "mok_cd", 10); // Wait a bit
        return;
    }
    
    // ================= HANDLE WINDUP =================
    var windup = getStored(npc, "mok_wind", 0);
    var casting = getStored(npc, "mok_casting", "");
    
    if (windup > 0) {
        windup--;
        setStored(npc, "mok_wind", windup);
        
        if (windup === 0 && casting) {
            executeJutsu(npc, casting, target);
            setStored(npc, "mok_casting", "");
        }
        return;
    }
    
    // ================= CHOOSE JUTSU =================
    var phase = getStored(npc, "mok_phase", 0);
    var weights = (phase === 1) ? WEIGHTS_AGGRESSIVE : WEIGHTS_BASE;
    
    // Distance-based adjustments
    var distance = distToTarget(npc, target);
    if (distance > 12) {
        weights.ARMATTACK += 15; // Prefer ranged attack
        weights.SPIKE -= 10;
    } else if (distance < 5) {
        weights.SPIKE += 15; // Prefer quick attack up close
        weights.WOOD_BURIAL -= 5;
    }
    
    // Remove WOOD_BURIAL from selection if on cooldown
    if (burialCD > 0 || getJutsuCooldown(npc, "WOOD_BURIAL") > 0) {
        weights.WOOD_BURIAL = 0;
    }
    
    var pick = weightedPick(weights);
    
    // ================= EXECUTE JUTSU =================
    if (pick === "WOOD_BURIAL") {
        // Windup for WOOD_BURIAL
        setStored(npc, "mok_wind", WINDUP_TICKS);
        setStored(npc, "mok_casting", "WOOD_BURIAL");
        setStored(npc, "mok_cd", 5); // Small cooldown even during windup
        
    } else if (pick === "ARMATTACK") {
        // Check if ARMATTACK is ready
        if (canCastJutsu(npc, "ARMATTACK")) {
            executeJutsu(npc, "ARMATTACK", target);
        } else {
            // Fallback to SPIKE
            startSpikeBurst(npc);
        }
        
    } else if (pick === "SPIKE") {
        startSpikeBurst(npc);
    }
}

function startSpikeBurst(npc) {
    // Check if SPIKE is ready
    if (canCastJutsu(npc, "SPIKE")) {
        // Rare voice line
        if (Math.random() < 0.15) {
            try { npc.say(SAYINGS.SPIKE[0]); } catch(e) {}
        }
        
        // Start burst
        setStored(npc, "spike_burst", 1);
        setStored(npc, "spike_count", 0);
        setStored(npc, "spike_delay", 0);
    } else {
        // SPIKE on cooldown, wait a bit
        setStored(npc, "mok_cd", 10);
    }
}

// ================= EVENT HANDLERS =================
function attacked(event) {
    var npc = event.npc;
    var attacker = event.source.getTrueSource();
    
    if (attacker && Math.random() < 0.25) {
        // Reduce cooldowns when attacked
        var currentCD = getStored(npc, "mok_cd", 0);
        setStored(npc, "mok_cd", Math.max(0, currentCD - 8));
        
        // Small chance to counter with SPIKE
        if (Math.random() < 0.3 && canCastJutsu(npc, "SPIKE")) {
            try {
                var me = npc.getMCEntity();
                var stack = new ItemStack(ItemMokuton.block);
                ItemMokuton.SPIKE.jutsu.createJutsu(stack, me, 0.9);
                setJutsuCooldown(npc, "SPIKE", 10);
            } catch(e) {}
        }
    }
}

function target(event) {
    var npc = event.npc;
    var target = event.target;
    
    if (target) {
        // Reset some cooldowns when acquiring new target
        setStored(npc, "mok_cd", 0);
    }
}

function kill(event) {
    // Reset burst state after kill
    var npc = event.npc;
    setStored(npc, "spike_burst", 0);
    setStored(npc, "spike_count", 0);
    setStored(npc, "spike_delay", 0);
    setStored(npc, "mok_cd", 5); // Short cooldown to chain kills
}