import { world, system, BlockPermutation } from "@minecraft/server";

// gets what type of tnt it is
function getIgnitedId(typeId) {
    if (typeId.startsWith("destructive:tnt_")) {
        return `${typeId}_ignited`;
    }
    return null;
}

/// Ignite w/ flint and steel
world.beforeEvents.itemUseOn.subscribe((event) => {
    const { itemStack, block, source: player } = event;

    if (!itemStack || (itemStack.typeId !== "minecraft:flint_and_steel" && itemStack.typeId !== "minecraft:fire_charge")) return;

    const ignitedId = getIgnitedId(block.typeId);
    if (!ignitedId) return;

    event.cancel = true;

    const dimension = player.dimension;
    const loc = block.location;
    const spawnPos = { x: loc.x + 0.5, y: loc.y, z: loc.z + 0.5 };

    system.run(() => {
        try {
            dimension.getBlock(loc)?.setType("minecraft:air");
            const tntEntity = dimension.spawnEntity(ignitedId, spawnPos);

            tntEntity.applyImpulse({
                x: (Math.random() - 0.5) * 0.2,
                y: 0.25,
                z: (Math.random() - 0.5) * 0.2
            });

            dimension.playSound("random.fuse", spawnPos);
        } catch (e) {
            console.warn(`[Script Error]: Could not spawn ${ignitedId}. Does the entity exist?`);
        }
    });
});

/// Chain Reaction Logic
let blocksToIgnite = [];

world.beforeEvents.explosion.subscribe((event) => {
    const impactedBlocks = event.getImpactedBlocks();

    blocksToIgnite = impactedBlocks
        .filter(block => getIgnitedId(block.typeId) !== null)
        .map(block => ({
            location: block.location,
            dimension: event.dimension,
            ignitedId: getIgnitedId(block.typeId),
            typeId: block.typeId
        }));
});

world.afterEvents.explosion.subscribe(() => {
    if (blocksToIgnite.length === 0) return;

    const queue = [...blocksToIgnite];
    blocksToIgnite = [];

    system.run(() => {
        for (const data of queue) {
            const { location, dimension, ignitedId, typeId } = data;
            const items = dimension.getEntities({
                type: "minecraft:item",
                location: location,
                closest: 1
            });
            if (items.length > 0) {
                const item = items[0];
                if (item.getComponent("item").itemStack.typeId === typeId) {
                    item.remove();
                }
            }
            let tntEntity = dimension.spawnEntity(ignitedId, {
                x: location.x + 0.5,
                y: location.y,
                z: location.z + 0.5
            });
            tntEntity.applyImpulse({
                x: (Math.random() - 0.5) * 0.2,
                y: 0.25,
                z: (Math.random() - 0.5) * 0.2
            });
            tntEntity.triggerEvent('quick_fuse')
        }
    });
});

// Redstone Logic
world.beforeEvents.worldInitialize.subscribe(event => {
    event.blockComponentRegistry.registerCustomComponent("destructive:redstone_ignite", {
        onTick(event) {
            const block = event.block;
            const pos = block.location;
            const dim = block.dimension;

            const directions = [
                { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 },
                { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 },
                { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 }
            ];

            const getPowerLevel = () => {
                let maxPower = 0;
                for (const d of directions) {
                    try {
                        const neighbor = dim.getBlock({ x: pos.x + d.x, y: pos.y + d.y, z: pos.z + d.z });
                        const p = neighbor.getRedstonePower();
                        if (p > maxPower) maxPower = p;
                    } catch (e) { }
                }
                return maxPower;
            };

            try {
                if (!block || block.typeId === "minecraft:air") return;

                if (getPowerLevel() > 0) {
                    const ignitedId = getIgnitedId(block.typeId);
                    if (!ignitedId) return;

                    system.run(() => {
                        if (dim.getBlock(pos)?.typeId === block.typeId) {
                            dim.getBlock(pos).setType("minecraft:air");

                            const spawnPos = { x: pos.x + 0.5, y: pos.y, z: pos.z + 0.5 };
                            const tntEntity = dim.spawnEntity(ignitedId, spawnPos);

                            tntEntity.applyImpulse({
                                x: (Math.random() - 0.5) * 0.2,
                                y: 0.25,
                                z: (Math.random() - 0.5) * 0.2
                            });

                            dim.playSound("random.fuse", spawnPos);
                        }
                    });
                }
            } catch (e) { }
        }
    });
})

// Knockback TNT Logic
world.afterEvents.dataDrivenEntityTrigger.subscribe((event) => {
    const { entity, eventId } = event;
    if (eventId === "destructive:knockback") {
        const loc = entity.location;
        const dim = entity.dimension;
        const targets = dim.getEntities({
            location: loc,
            maxDistance: 8,
        });
        for (const target of targets) {
            const dx = target.location.x - loc.x;
            const dz = target.location.z - loc.z;
            const distance = Math.sqrt(dx * dx + dz * dz);

            if (distance > 0) {
                target.applyImpulse({
                    x: (dx / distance) * 3,
                    y: 2,
                    z: (dz / distance) * 3
                });
            }
        }
        dim.playSound("random.explode", loc);
    }
});

// Glitched TNT Logic 
const concreteColors = [
    "white", "orange", "magenta", "light_blue", "yellow", "lime",
    "pink", "gray", "light_gray", "cyan", "purple", "blue", "brown",
    "green", "red", "black"
];
function* glitchGenerator(location, dimension, radius) {
    const startTime = Date.now();
    const duration = 10000;
    const centerX = Math.floor(location.x);
    const centerY = Math.floor(location.y);
    const centerZ = Math.floor(location.z);

    const affectedBlocks = [];
    for (let x = -radius; x <= radius; x++) {
        for (let y = -radius; y <= radius; y++) {
            for (let z = -radius; z <= radius; z++) {
                if (x * x + y * y + z * z <= radius * radius) {
                    const pos = { x: centerX + x, y: centerY + y, z: centerZ + z };
                    const block = dimension.getBlock(pos);
                    if (block && !block.isAir) {
                        affectedBlocks.push(pos);
                    }
                }
            }
        }
    }

    while (Date.now() - startTime < duration) {
        for (const pos of affectedBlocks) {
            const randomColor = concreteColors[Math.floor(Math.random() * concreteColors.length)];
            const block = dimension.getBlock(pos);
            block?.setPermutation(BlockPermutation.resolve(`minecraft:${randomColor}_concrete`));
        }

        const randomPitch = 0.5 + Math.random() * 1.5;
        dimension.playSound("beacon.deactivate", location, {
            pitch: randomPitch,
            volume: 0.6
        });

        if (Math.random() > 0.7) {
            dimension.playSound("conduit.deactivate", location, { pitch: 0.1, volume: 0.4 });
        }

        for (let i = 0; i < 3; i++) yield;
    }

    for (const pos of affectedBlocks) {
        const block = dimension.getBlock(pos);
        const isBlack = (pos.x + pos.y + pos.z) % 2 === 0;
        const finalColor = isBlack ? "black_concrete" : "magenta_concrete";
        block?.setPermutation(BlockPermutation.resolve(`minecraft:${finalColor}`));
    }

    dimension.playSound("random.glass", location, { pitch: 0.5 });
}
world.afterEvents.dataDrivenEntityTrigger.subscribe((event) => {
    if (event.eventId === "destructive:glitched") {
        event.entity.dimension.playSound("random.explode", event.entity.location);
        system.runJob(glitchGenerator(event.entity.location, event.entity.dimension, 5));
    }
});

// Large TNTs Logic
const TNT_SIZES = {
    "destructive:x50": { width: 20, depth: 15, variation: 5.0 },
    "destructive:x100": { width: 35, depth: 25, variation: 10.0 },
    "destructive:x500": { width: 70, depth: 45, variation: 12.0 }
};
const pendingExplosions = [];
world.afterEvents.dataDrivenEntityTrigger.subscribe((event) => {
    const config = TNT_SIZES[event.eventId];
    if (!config || !event.entity) return;
    const { x, y, z } = event.entity.location;
    const dimension = event.entity.dimension;
    const approxVolume = (4 / 3) * Math.PI * config.width * config.depth * config.width;
    const dropChance = 100 / approxVolume;
    const minChunkX = Math.floor((x - config.width) / 16);
    const maxChunkX = Math.floor((x + config.width) / 16);
    const minChunkZ = Math.floor((z - config.width) / 16);
    const maxChunkZ = Math.floor((z + config.width) / 16);
    for (let cx = minChunkX; cx <= maxChunkX; cx++) {
        for (let cz = minChunkZ; cz <= maxChunkZ; cz++) {
            const task = { cx, cz, origin: { x, y, z }, dimension, config, dropChance };
            if (!tryProcess(task)) {
                pendingExplosions.push(task);
            }
        }
    }
});
system.runInterval(() => {
    if (pendingExplosions.length === 0) return;
    for (let i = pendingExplosions.length - 1; i >= 0; i--) {
        if (tryProcess(pendingExplosions[i])) {
            pendingExplosions.splice(i, 1);
        }
    }
}, 5);
function tryProcess(task) {
    const { cx, cz, dimension, origin } = task;
    const chunkCenter = { x: cx * 16 + 8, y: origin.y, z: cz * 16 + 8 };
    try {
        const block = dimension.getBlock(chunkCenter);
        if (block && block.isValid()) {
            processChunkExplosion(task);
            return true;
        }
    } catch (e) { }
    return false;
}
function processChunkExplosion(task) {
    const UNBREAKABLE_BLOCKS = new Set([
        "minecraft:air",
        "minecraft:tnt",
        "minecraft:bedrock",
        "minecraft:barrier",
        "minecraft:command_block",
        "minecraft:structure_block",
        "minecraft:repeating_command_block",
        "minecraft:chain_command_block"
    ]);
    const { origin, dimension, config, dropChance, cx, cz } = task;
    const xMin = cx * 16;
    const zMin = cz * 16;
    const xMax = xMin + 15;
    const zMax = zMin + 15;
    for (let bx = xMin; bx <= xMax; bx++) {
        for (let bz = zMin; bz <= zMax; bz++) {
            for (let dy = -config.depth; dy <= config.depth; dy++) {
                const by = Math.floor(origin.y + dy);
                const dx = bx - origin.x;
                const dz = bz - origin.z;
                const noise = 1 + (Math.random() - 0.5) * (config.variation / 10);
                const dSquared = (dx * dx) / (config.width * config.width) +
                    (dy * dy) / (config.depth * config.depth) +
                    (dz * dz) / (config.width * config.width);
                if (dSquared <= (1 * noise)) {
                    try {
                        const block = dimension.getBlock({ x: bx, y: by, z: bz });
                        if (block?.isValid() && !UNBREAKABLE_BLOCKS.has(block.typeId) && !block.typeId.startsWith("destructive:tnt_")) {
                            const cmd = Math.random() < dropChance ? "destroy" : "";
                            dimension.runCommand(`setblock ${bx} ${by} ${bz} air ${cmd}`);
                        }
                    } catch (e) { }
                }
            }
        }
    }
}

// Nuke Logic
const CONFIG = { maxRadius: 25, expandRate: 1, fireChance: 0.5, outerFire: 25 };
const UNBREAKABLE = new Set(["minecraft:air", "minecraft:bedrock", "minecraft:barrier", "minecraft:command_block", "minecraft:structure_block", "minecraft:repeating_command_block", "minecraft:chain_command_block"]);
const active = [];
world.afterEvents.dataDrivenEntityTrigger.subscribe(e => {
    if (e.eventId !== "destructive:nuke" || !e.entity) return;
    const origin = e.entity.location;
    const dimension = e.entity.dimension;
    dimension.runCommand(`damage @a[x=${origin.x},y=${origin.y},z=${origin.z},r=50] 1000 entity_explosion`);
    const n = { origin: e.entity.location, dimension: e.entity.dimension, radius: 1, prev: 0, cloud: null };
    try { n.cloud = n.dimension.spawnEntity("destructive:boomcloud", n.origin); } catch { }
    active.push(n);
});
system.runInterval(() => {
    for (let i = active.length - 1; i >= 0; i--) {
        const n = active[i];
        const { origin, dimension, radius, prev } = n;
        const r2 = radius * radius, pr2 = prev * prev;
        for (let x = Math.floor(origin.x - radius); x <= Math.floor(origin.x + radius); x++)
            for (let y = Math.floor(origin.y - radius); y <= Math.floor(origin.y + radius); y++)
                for (let z = Math.floor(origin.z - radius); z <= Math.floor(origin.z + radius); z++) {
                    const dx = x - origin.x, dy = y - origin.y, dz = z - origin.z, dist = dx * dx + dy * dy + dz * dz;
                    if (dist <= pr2 || dist > r2) continue;
                    try {
                        const b = dimension.getBlock({ x, y, z });
                        if (!b?.isValid() || UNBREAKABLE.has(b.typeId)) continue;
                        dimension.runCommand(`setblock ${x} ${y} ${z} air`);
                        if (Math.random() < CONFIG.fireChance) dimension.runCommand(`setblock ${x} ${y} ${z} fire`);
                    } catch { }
                }
        const inner = radius, outer = radius + CONFIG.outerFire;
        const inner2 = inner * inner, outer2 = outer * outer;
        for (let x = Math.floor(origin.x - outer); x <= Math.floor(origin.x + outer); x++)
            for (let z = Math.floor(origin.z - outer); z <= Math.floor(origin.z + outer); z++) {
                const dx = x - origin.x, dz = z - origin.z, dist = dx * dx + dz * dz;
                if (dist <= inner2 || dist > outer2) continue;
                try {
                    for (let y = origin.y + 10; y >= origin.y - 10; y--) {
                        const g = dimension.getBlock({ x, y, z }), a = dimension.getBlock({ x, y: y + 1, z });
                        if (g?.isValid() && a?.isValid() && g.typeId !== "minecraft:air" && a.typeId === "minecraft:air") {
                            if (Math.random() < 0.5) dimension.runCommand(`setblock ${x} ${y + 1} ${z} fire`);
                            break;
                        }
                    }
                } catch { }
            }
        const scaleComponent = n.cloud.getComponent("minecraft:scale");
        if (scaleComponent) {
            const targetScale = 1 + n.radius / 15;
            scaleComponent.value = targetScale;
        }
        dimension.runCommand(`camerashake add @a 4 6 positional`);
        dimension.runCommand(`playsound ambient.weather.thunder @a ${origin.x} ${origin.y} ${origin.z} 10 0.5`);
        n.prev = n.radius;
        n.radius += CONFIG.expandRate;
        if (n.radius > CONFIG.maxRadius) active.splice(i, 1);
    }
}, 2);