import { world, system } from "@minecraft/server";
import * as mc from "@minecraft/server";

const STATE = {
  avoidBlocks: {},
  confusionTrapBlocks: {},
  fakeImpulseDoors: {},
  fakeImpulseDoorsFire: {},
  trolledBeds: {},
  fakeTorchLocations: [],
  trapBlocks: {},
  secretDoorBlocks: {},
  secretDoorActive: {},
  slimeTrapBlocks: {},
  teleportTrapBlocks: {},
  stormTrapBlocks: {},
  fakeSoundBlocks: {},
  speedFloorBlocks: {},
  chameleonBlocks: {},
  fallingBlocks: {},
};

const lastInteractTime = new Map();
const lastTrapTime1 = new Map();

const DP_KEY = "ka_troll:trap_state";

function saveTrapState() {
  const data = {
    avoidBlocks: STATE.avoidBlocks,
    confusionTrapBlocks: STATE.confusionTrapBlocks,
    fakeImpulseDoors: STATE.fakeImpulseDoors,
    fakeImpulseDoorsFire: STATE.fakeImpulseDoorsFire,
    trolledBeds: STATE.trolledBeds,
    fakeTorchLocations: STATE.fakeTorchLocations,
    trapBlocks: STATE.trapBlocks,
    secretDoorBlocks: STATE.secretDoorBlocks,
    slimeTrapBlocks: STATE.slimeTrapBlocks,
    teleportTrapBlocks: STATE.teleportTrapBlocks,
    stormTrapBlocks: STATE.stormTrapBlocks,
    fakeSoundBlocks: STATE.fakeSoundBlocks,
    speedFloorBlocks: STATE.speedFloorBlocks,
    chameleonBlocks: STATE.chameleonBlocks,
    fallingBlocks: STATE.fallingBlocks,
  };
  try {
    world.setDynamicProperty(DP_KEY, JSON.stringify(data));
  } catch (e) {
    console.warn("Error guardando estado de trampas:", e);
  }
}

function loadTrapState() {
  try {
    const raw = world.getDynamicProperty(DP_KEY);
    if (!raw) return;
    const data = JSON.parse(raw);

    Object.assign(STATE.avoidBlocks, data.avoidBlocks ?? {});
    Object.assign(STATE.confusionTrapBlocks, data.confusionTrapBlocks ?? {});
    Object.assign(STATE.fakeImpulseDoors, data.fakeImpulseDoors ?? {});
    Object.assign(STATE.fakeImpulseDoorsFire, data.fakeImpulseDoorsFire ?? {});
    Object.assign(STATE.trolledBeds, data.trolledBeds ?? {});
    Object.assign(STATE.trapBlocks, data.trapBlocks ?? {});
    Object.assign(STATE.secretDoorBlocks, data.secretDoorBlocks ?? {});
    Object.assign(STATE.slimeTrapBlocks, data.slimeTrapBlocks ?? {});
    Object.assign(STATE.teleportTrapBlocks, data.teleportTrapBlocks ?? {});
    Object.assign(STATE.stormTrapBlocks, data.stormTrapBlocks ?? {});
    Object.assign(STATE.fakeSoundBlocks, data.fakeSoundBlocks ?? {});
    Object.assign(STATE.speedFloorBlocks, data.speedFloorBlocks ?? {});
    Object.assign(STATE.chameleonBlocks, data.chameleonBlocks ?? {});
    Object.assign(STATE.fallingBlocks, data.fallingBlocks ?? {});

    if (Array.isArray(data.fakeTorchLocations)) {
      STATE.fakeTorchLocations = data.fakeTorchLocations;
    }
  } catch (e) {
    console.warn("Error leyendo estado de trampas:", e);
  }
}

system.runTimeout(() => {
  loadTrapState();
}, 1);

function _distance(a, b) {
  const dx = a.x - b.x,
    dy = a.y - b.y,
    dz = a.z - b.z;
  return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
function _changeBlock(loc, typeId) {
  const d = world.getDimension("overworld");
  d.runCommandAsync(`setblock ${loc.x} ${loc.y} ${loc.z} ${typeId}`);
}
function _rand(min, max) {
  return Math.random() * (max - min) + min;
}

// --------------------------------------------------
// anvil.js
// --------------------------------------------------
world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const block = ev.block;
  if (block.typeId === "ka_troll:fake_anvil") {
    const { x, y, z } = block.location;
    system.run(() =>
      ev.player.runCommandAsync(`setblock ${x} ${y} ${z} air`)
    );
  }
});

// --------------------------------------------------
// apple_troll.js
// --------------------------------------------------
const TELEPORT_RADIUS = 100;
world.beforeEvents.itemUse.subscribe((ev) => {
  const player = ev.source;
  const itemStack = ev.itemStack;
  if (itemStack?.typeId === "ka_troll:apple_troll") {
    system.run(() => {
      player.runCommandAsync(`clear @s ka_troll:apple_troll 0 1`);
      const p = player.location;
      player.runCommandAsync(
        `spreadplayers ${p.x} ${p.z} 0 ${TELEPORT_RADIUS} @s`
      );
    });
  }
});

// --------------------------------------------------
// avoid_blocks.js
// --------------------------------------------------
const IMPULSE_STRENGTH_AVOID = 1.5;
world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const item = ev.itemStack;
  const block = ev.block;
  if (item?.typeId === "ka_troll:avoid_blocks") {
    system.run(() => {
      const k = `${block.location.x},${block.location.y},${block.location.z}`;
      STATE.avoidBlocks[k] = { type: block.typeId };
      saveTrapState();
    });
  }
});
system.runInterval(() => {
  const map = STATE.avoidBlocks;
  for (const player of world.getPlayers()) {
    const lp = player.location;
    const pos = {
      x: Math.floor(lp.x),
      y: Math.floor(lp.y) - 1,
      z: Math.floor(lp.z),
    };
    const k = `${pos.x},${pos.y},${pos.z}`;
    if (map[k]) {
      const blockType = map[k].type;
      const block = player.dimension.getBlock(pos);
      if (block?.typeId === blockType) {
        const ang = Math.random() * Math.PI * 2;
        const dx = Math.cos(ang);
        const dz = Math.sin(ang);
        player.applyKnockback(
          dx,
          dz,
          IMPULSE_STRENGTH_AVOID,
          IMPULSE_STRENGTH_AVOID
        );
        player.runCommandAsync(
          `playsound random.orb @s ${lp.x} ${lp.y} ${lp.z}`
        );
      }
    }
  }
}, 1);

// --------------------------------------------------
// block_confusion.js
// --------------------------------------------------
world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const item = ev.itemStack;
  const block = ev.block;
  if (item?.typeId === "ka_troll:stone_of_confusion") {
    system.run(() => {
      const k = `${block.location.x},${block.location.y},${block.location.z}`;
      STATE.confusionTrapBlocks[k] = block.typeId;
      saveTrapState();
    });
  }
});
system.runInterval(() => {
  const map = STATE.confusionTrapBlocks;
  for (const player of world.getPlayers()) {
    const lp = player.location;
    const pos = {
      x: Math.floor(lp.x),
      y: Math.floor(lp.y - 0.1),
      z: Math.floor(lp.z),
    };
    const k = `${pos.x},${pos.y},${pos.z}`;
    if (map[k]) {
      const blockType = map[k];
      const block = player.dimension.getBlock(pos);
      if (block?.typeId === blockType) {
        player.runCommandAsync(`camerashake add @s 2 10`);
      }
    }
  }
}, 1);

// --------------------------------------------------
// book.js
// --------------------------------------------------
mc.world.afterEvents.entityHitEntity.subscribe((data) => {
  if (data.damagingEntity?.typeId !== "minecraft:player") return;
  if (data.hitEntity?.typeId !== "ka_troll:troll_guide") return;
  const player = data.damagingEntity;
  const hitEntity = data.hitEntity;
  const lookDirection = player.getViewDirection();
  const deltaX = hitEntity.location.x - player.location.x;
  const deltaZ = hitEntity.location.z - player.location.z;
  const angle = Math.atan2(deltaZ, deltaX);
  const playerLookAngle = Math.atan2(lookDirection.z, lookDirection.x);
  const angleDifference =
    (angle - playerLookAngle + Math.PI * 2) % (Math.PI * 2);
  const centerRange = Math.PI / 32;

  if (angleDifference < centerRange || angleDifference > Math.PI * 2 - centerRange) {
    mc.world.playSound("cp.book.close", hitEntity.location);
    hitEntity.triggerEvent("cp:time_to_despawn");
  } else if (angleDifference > Math.PI) {
    mc.world.playSound("cp.book.page", hitEntity.location);
    hitEntity.playAnimation("animation.base_book.left");
    hitEntity.triggerEvent("cp:next_page");
  } else {
    mc.world.playSound("cp.book.page", hitEntity.location);
    hitEntity.playAnimation("animation.base_book.right");
    hitEntity.triggerEvent("cp:back_page");
  }
});

// --------------------------------------------------
// bow_fake.js
// --------------------------------------------------
const PROJECTILE_ITEM_TYPE = "minecraft:arrow";
const PROJECTILE_ENTITY_TYPE = "minecraft:arrow";
function _hasAmmo(player) {
  const inv = player.getComponent("minecraft:inventory").container;
  for (let i = 0; i < inv.size; i++) {
    const it = inv.getItem(i);
    if (it && it.typeId === PROJECTILE_ITEM_TYPE && it.amount > 0) return i;
  }
  return -1;
}
world.afterEvents.itemReleaseUse.subscribe((ev) => {
  const player = ev.source;
  if (ev.itemStack?.typeId === "ka_troll:bow") {
    const ammoSlot = _hasAmmo(player);
    if (ammoSlot === -1) {
      player.sendMessage("§cYou need Frostfire Arrows to shoot!");
      return;
    }
    const inv = player.getComponent("minecraft:inventory").container;
    const ammoItem = inv.getItem(ammoSlot);
    if (ammoItem) {
      if (ammoItem.amount > 1) {
        ammoItem.amount -= 1;
        inv.setItem(ammoSlot, ammoItem);
      } else {
        inv.setItem(ammoSlot, undefined);
      }
    }
    const { dimension, location } = player;
    ev.cancel = true;
    const frost = dimension.spawnEntity(PROJECTILE_ENTITY_TYPE, {
      x: location.x,
      y: location.y + 1.5,
      z: location.z,
    });
    const projectile = frost.getComponent("minecraft:projectile");
    projectile.owner = player;
    projectile.shoot({
      x: _rand(-1, 1),
      y: _rand(-0.5, 1),
      z: _rand(-1, 1),
    });
  }
});

// --------------------------------------------------
// bucket_troll.js
// --------------------------------------------------
world.afterEvents.itemUse.subscribe((ev) => {
  const player = ev.source;
  const item = ev.itemStack;
  if (item?.typeId === "ka_troll:bucket_troll") {
    system.run(() => {
      player.runCommandAsync(`clear @s ka_troll:bucket_troll 1`);
      player.runCommandAsync(`summon minecraft:guardian ~ ~ ~`);
    });
  }
});

// --------------------------------------------------
// cake.js
// --------------------------------------------------
let cakeOnce = false;
world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const block = ev.block;
  const player = ev.player;
  const loc = block.location;
  if (block.typeId === "ka_troll:cake" && !cakeOnce) {
    cakeOnce = true;
    system.run(() => {
      player.runCommandAsync(
        `summon ka_troll:explode_func ${loc.x} ${loc.y} ${loc.z}`
      );
      system.runTimeout(() => {
        cakeOnce = false;
      }, 20);
    });
  }
});

// --------------------------------------------------
// controllos_crazy.js
// --------------------------------------------------
const EFFECT_DURATION = 200; // 10s
const IMPULSE_STRENGTH_FOOD = 0.5;
const affectedPlayers = new Map();
world.beforeEvents.itemUse.subscribe((ev) => {
  const player = ev.source;
  const itemStack = ev.itemStack;
  if (itemStack?.typeId === "ka_troll:food") {
    affectedPlayers.set(player.id, system.currentTick);
  }
});
system.runInterval(() => {
  const now = system.currentTick;
  for (const [playerId, start] of affectedPlayers) {
    const players = world.getPlayers({ id: playerId });
    if (!players.length) {
      affectedPlayers.delete(playerId);
      continue;
    }
    const player = players[0];
    if (now - start >= EFFECT_DURATION) {
      affectedPlayers.delete(playerId);
      continue;
    }
    const rx = (Math.random() - 1) * IMPULSE_STRENGTH_FOOD;
    const rz = (Math.random() - 1) * IMPULSE_STRENGTH_FOOD;
    player.applyKnockback(rx, rz, IMPULSE_STRENGTH_FOOD, 0);
  }
}, 5);

// --------------------------------------------------
// door_expulse.js
// --------------------------------------------------
const KNOCKBACK_STRENGTH_DOOR = 1.5;
world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const item = ev.itemStack;
  const block = ev.block;
  if (item?.typeId === "ka_troll:fake_impulse_door") {
    system.run(() => {
      const k = `${block.location.x},${block.location.y},${block.location.z}`;
      STATE.fakeImpulseDoors[k] = {
        type: block.typeId,
        activatorPosition: ev.player.location,
      };
      saveTrapState();
    });
  }
});
system.runInterval(() => {
  const map = STATE.fakeImpulseDoors;
  for (const player of world.getPlayers()) {
    const lp = player.location;
    const pos = {
      x: Math.floor(lp.x),
      y: Math.floor(lp.y),
      z: Math.floor(lp.z),
    };
    const k = `${pos.x},${pos.y},${pos.z}`;
    if (map[k]) {
      const blockData = map[k];
      const block = player.dimension.getBlock(pos);
      if (block?.typeId === blockData.type) {
        const dx = lp.x - blockData.activatorPosition.x;
        const dz = lp.z - blockData.activatorPosition.z;
        const dist = Math.max(Math.sqrt(dx * dx + dz * dz), 0.0001);
        player.applyKnockback(
          dx / dist,
          dz / dist,
          KNOCKBACK_STRENGTH_DOOR,
          KNOCKBACK_STRENGTH_DOOR
        );
        player.runCommandAsync(
          `playsound random.orb @s ${lp.x} ${lp.y} ${lp.z}`
        );
      }
    }
  }
}, 1);

// --------------------------------------------------
// rabbit_stew.js
// --------------------------------------------------
const JUMP_DURATION = 200;
const JUMP_STRENGTH = 0.5;
const jumpingPlayers = new Map();
world.beforeEvents.itemUse.subscribe((ev) => {
  const player = ev.source;
  const itemStack = ev.itemStack;
  if (itemStack?.typeId === "ka_troll:rabbit_stew_troll") {
    system.run(() => {
      player.runCommandAsync(`clear @s ka_troll:rabbit_stew_troll 1`);
      jumpingPlayers.set(player.id, system.currentTick);
    });
  }
});
system.runInterval(() => {
  const now = system.currentTick;
  for (const [playerId, startTime] of jumpingPlayers) {
    const players = world.getPlayers({ id: playerId });
    if (!players.length) {
      jumpingPlayers.delete(playerId);
      continue;
    }
    const player = players[0];
    if (now - startTime >= JUMP_DURATION) {
      jumpingPlayers.delete(playerId);
      continue;
    }
    const loc = player.location;
    const below = {
      x: Math.floor(loc.x),
      y: Math.floor(loc.y - 0.1),
      z: Math.floor(loc.z),
    };
    const blockBelow = player.dimension.getBlock(below);
    if (blockBelow && blockBelow.typeId !== "minecraft:air") {
      player.applyKnockback(0, 0, JUMP_STRENGTH, JUMP_STRENGTH);
    }
  }
}, 10);

// --------------------------------------------------
// door_fire.js
// --------------------------------------------------
world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const item = ev.itemStack;
  const block = ev.block;
  if (item?.typeId === "ka_troll:door_fire_troll") {
    system.run(() => {
      const k = `${block.location.x},${block.location.y},${block.location.z}`;
      STATE.fakeImpulseDoorsFire[k] = block.typeId;
      saveTrapState();
    });
  }
});
system.runInterval(() => {
  const map = STATE.fakeImpulseDoorsFire;
  for (const player of world.getPlayers()) {
    const lp = player.location;
    const pos = {
      x: Math.floor(lp.x),
      y: Math.floor(lp.y),
      z: Math.floor(lp.z),
    };
    const k = `${pos.x},${pos.y},${pos.z}`;
    if (map[k]) {
      const typeId = map[k];
      const block = player.dimension.getBlock(pos);
      if (block?.typeId === typeId) {
        player.setOnFire(10);
        player.runCommandAsync(
          `playsound random.orb @s ${lp.x} ${lp.y} ${lp.z}`
        );
      }
    }
  }
}, 1);

// --------------------------------------------------
// door_trap.js (beds)
// --------------------------------------------------
world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const player = ev.player;
  const block = ev.block;
  const item = ev.itemStack;
  if (item?.typeId === "ka_troll:bed_trap" && block.typeId === "minecraft:bed") {
    system.run(() => {
      const k = `${block.location.x},${block.location.y},${block.location.z}`;
      STATE.trolledBeds[k] = {
        type: block.typeId,
        isSneaking: player.isSneaking,
      };
      saveTrapState();
    });
  }
});
world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const player = ev.player;
  const block = ev.block;
  const k = `${block.location.x},${block.location.y},${block.location.z}`;
  const trolled = STATE.trolledBeds;
  if (block.typeId === "minecraft:bed" && trolled[k]) {
    system.run(() => {
      const last = lastInteractTime.get(player.id) ?? -999999;
      const now = system.currentTick;
      if (now - last < 20) return;
      lastInteractTime.set(player.id, now);

      const bedData = trolled[k];
      if (bedData.isSneaking) {
        player.applyKnockback(0, 0, 0, 2);
      } else {
        player.dimension.spawnEntity("ka_troll:explode_func", block.location);
      }
      delete trolled[k];
      saveTrapState();
    });
  }
});

// --------------------------------------------------
// fake_torch.js  (arreglada para evitar parpadeo con varios jugadores)
// --------------------------------------------------
world.afterEvents.playerPlaceBlock.subscribe((ev) => {
  if (ev.block.typeId === "ka_troll:fake_torch") {
    const p = ev.block.location;
    STATE.fakeTorchLocations.push({ x: p.x, y: p.y, z: p.z });
    saveTrapState();
  }
});

world.afterEvents.playerBreakBlock.subscribe((ev) => {
  if (ev.block.typeId === "ka_troll:fake_torch") {
    const p = ev.block.location;
    STATE.fakeTorchLocations = STATE.fakeTorchLocations.filter(
      (l) => !(l.x === p.x && l.y === p.y && l.z === p.z)
    );
    saveTrapState();
  }
});

system.runInterval(() => {
  if (!STATE.fakeTorchLocations.length) return;

  const players = [...world.getPlayers()];
  if (!players.length) return;

  const list = [...STATE.fakeTorchLocations];
  const dim = world.getDimension("overworld");

  for (const loc of list) {
    const block = dim.getBlock(loc);
    if (!block) {
      STATE.fakeTorchLocations = STATE.fakeTorchLocations.filter(
        (l) => !(l.x === loc.x && l.y === loc.y && l.z === loc.z)
      );
      saveTrapState();
      continue;
    }

    // distancia mínima de cualquier jugador a ESTA antorcha
    let minDist = Infinity;
    for (const p of players) {
      const d = _distance(p.location, loc);
      if (d < minDist) minDist = d;
    }
    const playerIsNear = minDist <= 8;

    if (playerIsNear && block.typeId === "minecraft:torch") {
      _changeBlock(loc, "ka_troll:fake_torch");
    } else if (!playerIsNear && block.typeId === "ka_troll:fake_torch") {
      _changeBlock(loc, "minecraft:torch");
    }
  }
}, 1);

// --------------------------------------------------
// fake_blocks.js
// --------------------------------------------------
world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const item = ev.itemStack;
  const block = ev.block;

  if (item?.typeId === "ka_troll:block_trap") {
    if (
      block.typeId === "minecraft:bedrock" ||
      block.typeId === "minecraft:barrier"
    )
      return;

    system.run(() => {
      const k = `${block.location.x},${block.location.y},${block.location.z}`;
      STATE.trapBlocks[k] = block.typeId;
      saveTrapState();
    });
  }
});

system.runInterval(() => {
  const map = STATE.trapBlocks;

  for (const player of world.getPlayers()) {
    const lp = player.location;
    const pos = {
      x: Math.floor(lp.x),
      y: Math.floor(lp.y - 0.4),
      z: Math.floor(lp.z),
    };
    const k = `${pos.x},${pos.y},${pos.z}`;

    if (map[k]) {
      const typeId = map[k];
      const block = player.dimension.getBlock(pos);

      if (block?.typeId === typeId) {
        player.runCommandAsync(
          `setblock ${pos.x} ${pos.y} ${pos.z} minecraft:air`
        );
        player.runCommandAsync(
          `playsound random.door_open @s ${pos.x} ${pos.y} ${pos.z}`
        );
        delete map[k];
        saveTrapState();
      } else {
        delete map[k];
        saveTrapState();
      }
    }
  }
}, 1);

// --------------------------------------------------
// fake_door.js
// --------------------------------------------------
if (!STATE.secretDoorBlocks) STATE.secretDoorBlocks = {};
if (!STATE.secretDoorActive) STATE.secretDoorActive = {};

const SECRET_DOOR_ITEM = "ka_troll:troll_item";
const SECRET_DOOR_HIDE_TICKS = 30;

world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const item = ev.itemStack;
  const block = ev.block;
  if (item?.typeId !== SECRET_DOOR_ITEM) return;

  system.run(() => {
    const k = `${block.location.x},${block.location.y},${block.location.z}`;
    STATE.secretDoorBlocks[k] = block.typeId;
    saveTrapState();
    ev.player.runCommandAsync(
      `playsound random.door_close @s ${block.location.x} ${block.location.y} ${block.location.z}`
    );
  });
});

world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const block = ev.block;
  const k = `${block.location.x},${block.location.y},${block.location.z}`;
  const map = STATE.secretDoorBlocks;

  if (!map[k]) return;
  if (STATE.secretDoorActive[k]) return;

  system.run(() => {
    const typeId = map[k];
    const current = ev.player.dimension.getBlock(block.location);
    if (!current || current.typeId !== typeId) return;

    STATE.secretDoorActive[k] = true;

    ev.player.runCommandAsync(
      `setblock ${block.location.x} ${block.location.y} ${block.location.z} minecraft:air`
    );
    ev.player.runCommandAsync(
      `playsound random.door_open @s ${block.location.x} ${block.location.y} ${block.location.z}`
    );

    system.runTimeout(() => {
      ev.player.runCommandAsync(
        `setblock ${block.location.x} ${block.location.y} ${block.location.z} ${typeId}`
      );
      ev.player.runCommandAsync(
        `playsound random.door_close @s ${block.location.x} ${block.location.y} ${block.location.z}`
      );

      delete STATE.secretDoorBlocks[k];
      delete STATE.secretDoorActive[k];
      saveTrapState();
    }, SECRET_DOOR_HIDE_TICKS);
  });
});

// --------------------------------------------------
// fake_pickaxe.js
// --------------------------------------------------
world.afterEvents.playerBreakBlock.subscribe((ev) => {
  const player = ev.player;
  const mainhand = player
    .getComponent("equippable")
    ?.getEquipment("Mainhand");
  const itemId = mainhand?.typeId || "";
  if (itemId === "ka_troll:pickaxe_troll") {
    const block = ev.block;
    const dim = block.dimension;
    const p = block.location;
    const W = 5,
      H = 4,
      D = 5;
    const sx = p.x - Math.floor(W / 2),
      sy = p.y - Math.floor(H / 2),
      sz = p.z - Math.floor(D / 2);
    const ex = sx + W - 1,
      ey = sy + H - 1,
      ez = sz + D - 1;
    dim.runCommand(`/fill ${sx} ${sy} ${sz} ${ex} ${ey} ${ez} air destroy`);
    const pl = player.location;
    const dsx = Math.floor(pl.x),
      dsy = Math.floor(pl.y) - 5,
      dsz = Math.floor(pl.z);
    const dex = dsx,
      dey = Math.floor(pl.y) - 1,
      dez = dsz;
    dim.runCommand(`/fill ${dsx} ${dsy} ${dsz} ${dex} ${dey} ${dez} air destroy`);
    player.applyDamage(2);
  }
});

// --------------------------------------------------
// fake_water.js
// --------------------------------------------------
const playersInFakeWater = new Set();
system.runInterval(() => {
  for (const player of world.getPlayers()) {
    const pos = {
      x: Math.floor(player.location.x),
      y: Math.floor(player.location.y),
      z: Math.floor(player.location.z),
    };
    const block = player.dimension.getBlock(pos);
    if (block?.typeId === "ka_troll:water_fake") {
      player.applyDamage(2);
      playersInFakeWater.add(player);
    } else {
      playersInFakeWater.delete(player);
    }
  }
}, 1);

// --------------------------------------------------
// phantom.js
// --------------------------------------------------
system.runInterval(() => {
  const overworld = world.getDimension("overworld");
  for (const player of world.getPlayers()) {
    const pl = player.location;
    for (const entity of overworld.getEntities()) {
      if (entity.typeId === "ka_troll:phantom") {
        const el = entity.location;
        const dx = pl.x - el.x,
          dy = pl.y - el.y,
          dz = pl.z - el.z;
        const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
        if (distance < 3) {
          entity.remove();
        }
      }
    }
  }
}, 1);

// --------------------------------------------------
// troll_villager
// --------------------------------------------------
system.runInterval(() => {
  const overworld = world.getDimension("overworld");
  for (const player of world.getPlayers()) {
    const pl = player.location;
    for (const entity of overworld.getEntities()) {
      if (entity.typeId === "ka_troll:troll_villager") {
        const el = entity.location;
        const dx = pl.x - el.x,
          dy = pl.y - el.y,
          dz = pl.z - el.z;
        const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);

        if (distance < 3) {
          for (let i = 0; i < 30; i++) {
            const offsetX = (Math.random() - 0.5) * 10;
            const offsetZ = (Math.random() - 0.5) * 10;
            const spawnX = pl.x + offsetX;
            const spawnY = pl.y + 15;
            const spawnZ = pl.z + offsetZ;

            overworld.runCommandAsync(
              `summon minecraft:arrow ${spawnX} ${spawnY} ${spawnZ}`
            );
          }

          entity.remove();
        }
      }
    }
  }
}, 1);

// --------------------------------------------------
// troll_witches
// --------------------------------------------------
system.runInterval(() => {
  const overworld = world.getDimension("overworld");
  for (const player of world.getPlayers()) {
    const pl = player.location;
    for (const entity of overworld.getEntities()) {
      if (entity.typeId === "ka_troll:troll_witches") {
        const el = entity.location;
        const dx = pl.x - el.x,
          dy = pl.y - el.y,
          dz = pl.z - el.z;
        const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
        if (distance < 3) {
          for (let i = 0; i < 3; i++) {
            overworld.runCommandAsync(
              `summon minecraft:tnt ${el.x} ${el.y + 10} ${el.z}`
            );
          }
          entity.remove();
        }
      }
    }
  }
}, 1);

// --------------------------------------------------
// rotten_fresh.js
// --------------------------------------------------
const ATTRACTION_RADIUS = 20;
function hasRottenFlesh(player) {
  const mainhand = player
    .getComponent("equippable")
    ?.getEquipment("Mainhand");
  return mainhand?.typeId === "ka_troll:rotten_flesh";
}
function moveZombiesTowardsPlayer(player) {
  const dimension = player.dimension;
  const playerLocation = player.location;
  const zombies = dimension.getEntities({
    type: "minecraft:zombie",
    location: playerLocation,
    maxDistance: ATTRACTION_RADIUS,
  });
  zombies.forEach((zombie) => {
    const zLoc = zombie.location;
    const dx = playerLocation.x - zLoc.x;
    const dy = playerLocation.y - zLoc.y;
    const dz = playerLocation.z - zLoc.z;
    const dist = Math.sqrt(dx * dx + dy * dy + dz * dz) || 0.001;
    const nx = dx / dist,
      ny = dy / dist,
      nz = dz / dist;
    zombie.teleport(
      {
        x: zLoc.x + nx * 0.5,
        y: zLoc.y + ny * 0.5,
        z: zLoc.z + nz * 0.5,
      },
      { dimension, rotation: { x: 0, y: 0 }, facingLocation: playerLocation }
    );
  });
}
system.runInterval(() => {
  for (const player of world.getPlayers()) {
    if (hasRottenFlesh(player)) {
      moveZombiesTowardsPlayer(player);
    }
  }
}, 10);

// --------------------------------------------------
// slime_troll.js
// --------------------------------------------------
const DETECTION_MAX = 5;

world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const block = ev.block;
  const item = ev.itemStack;

  if (item?.typeId === "ka_troll:slime_troll") {
    if (
      block.typeId === "minecraft:bedrock" ||
      block.typeId === "minecraft:barrier"
    )
      return;

    system.run(() => {
      const k = `${block.location.x},${block.location.y},${block.location.z}`;
      STATE.slimeTrapBlocks[k] = block.typeId;
      saveTrapState();
    });
  }
});

system.runInterval(() => {
  const map = STATE.slimeTrapBlocks;
  const dim = world.getDimension("overworld");

  for (const k in map) {
    const [x, y, z] = k.split(",").map(Number);
    const loc = { x, y, z };
    const block = dim.getBlock(loc);
    if (!block) continue;

    let playerAbove = false;

    for (const player of dim.getEntities({ type: "minecraft:player" })) {
      const p = player.location;
      const px = Math.floor(p.x),
        py = Math.floor(p.y),
        pz = Math.floor(p.z);

      if (px === x && pz === z && py > y && py <= y + DETECTION_MAX) {
        playerAbove = true;
        break;
      }
    }

    if (playerAbove) _changeBlock(loc, "minecraft:slime");
    else _changeBlock(loc, map[k]);
  }
}, 20);

// --------------------------------------------------
// spikes.js
// --------------------------------------------------
const lastDamageTimes = new Map();

system.runInterval(() => {
  const currentTime = system.currentTick;

  world.getPlayers().forEach((player) => {
    const pl = player.location;
    const below = {
      x: Math.floor(pl.x),
      y: Math.floor(pl.y - 0.3),
      z: Math.floor(pl.z),
    };
    const blockBelow = player.dimension.getBlock(below);

    if (blockBelow?.typeId === "ka_troll:spikes") {
      const lastTime = lastDamageTimes.get(player.id) || 0;

      if (currentTime - lastTime >= 1) {
        player.applyDamage(2);
        lastDamageTimes.set(player.id, currentTime);
      }
    }
  });
}, 1);

// --------------------------------------------------
// tnt_fake.js
// --------------------------------------------------
world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const player = ev.player;
  const block = ev.block;
  const item = ev.itemStack;

  if (!item) return;

  if (
    item.typeId === "minecraft:flint_and_steel" &&
    block.typeId === "ka_troll:fake_tnt"
  ) {
    const l = block.location;

    player.runCommandAsync(`setblock ${l.x} ${l.y} ${l.z} minecraft:air`);

    const golpes = 2;
    const intervalo = 10;

    for (let i = 0; i < golpes; i++) {
      system.runTimeout(() => {
        try {
          player.runCommandAsync(`damage @s 2 fire`);
        } catch (e) {}
      }, i * intervalo);
    }
  }
});

// --------------------------------------------------
// random_tp.js  (Troll Teleport: bloque ya NO desaparece)
// --------------------------------------------------
const TELEPORT_RADIUS_RT = 50;
const COOLDOWN_TIME = 20;
world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const block = ev.block;
  const item = ev.itemStack;
  if (item?.typeId === "ka_troll:block_teleport_trap") {
    system.run(() => {
      const k = `${block.location.x},${block.location.y},${block.location.z}`;
      STATE.teleportTrapBlocks[k] = block.typeId;
      saveTrapState();
    });
  }
});
system.runInterval(() => {
  const map = STATE.teleportTrapBlocks;
  world.getPlayers().forEach((player) => {
    const pl = player.location;
    const below = {
      x: Math.floor(pl.x),
      y: Math.floor(pl.y - 0.4),
      z: Math.floor(pl.z),
    };
    const k = `${below.x},${below.y},${below.z}`;
    if (map[k]) {
      const blockType = map[k];
      const block = player.dimension.getBlock(below);
      if (block?.typeId === blockType) {
        const last = lastTrapTime1.get(player.id) ?? -999999;
        const now = system.currentTick;
        if (now - last < COOLDOWN_TIME) return;
        lastTrapTime1.set(player.id, now);

        // YA NO SE BORRA EL BLOQUE, solo teletransporta y reproduce el sonido
        player.runCommandAsync(
          `spreadplayers ${below.x} ${below.z} 20 ${TELEPORT_RADIUS_RT} @p`
        );
        player.runCommandAsync(
          `playsound random.orb @s ${below.x} ${below.y} ${below.z}`
        );
      }
    }
  });
}, 1);

// --------------------------------------------------
// rod.js
// --------------------------------------------------
world.afterEvents.itemUse.subscribe((ev) => {
  const player = ev.source;
  const item = ev.itemStack;
  if (item?.typeId === "ka_troll:explosive_fishing") {
    player.runCommandAsync(`summon ka_troll:explode_func ~ ~ ~`);
    player.runCommandAsync(`clear @s ka_troll:explosive_fishing 0 1`);
  }
});

// --------------------------------------------------
// troll_sword.js
// --------------------------------------------------
mc.world.afterEvents.entityHurt.subscribe((ev) => {
  const attacker = ev.damageSource?.damagingEntity;
  if (!attacker || attacker.typeId !== "minecraft:player") return;

  const mainhand = attacker
    .getComponent("equippable")
    ?.getEquipment("Mainhand");
  if (mainhand?.typeId !== "ka_troll:troll_sword") return;

  if (ev.damage > 0) {
    attacker.applyDamage(ev.damage);
  }
});

// --------------------------------------------------
// troll_boots.js
// --------------------------------------------------
const BOOTS_ID = "ka_troll:troll_boots";
const TICK = 1;

system.runInterval(() => {
  for (const player of world.getPlayers()) {
    const feet = player.getComponent("equippable")?.getEquipment("Feet");
    if (feet?.typeId !== BOOTS_ID) continue;

    player.runCommandAsync(`effect @s slowness 2 255 true`);

    const loc = player.location;
    const below = {
      x: Math.floor(loc.x),
      y: Math.floor(loc.y - 0.1),
      z: Math.floor(loc.z),
    };
    const blockBelow = player.dimension.getBlock(below);

    if (blockBelow && blockBelow.typeId !== "minecraft:air") {
      const targetY = Math.floor(loc.y) + 0.001;
      if (loc.y > targetY + 0.01) {
        player.teleport(
          { x: loc.x, y: targetY, z: loc.z },
          { dimension: player.dimension, rotation: player.getRotation() }
        );
      }
    }
  }
}, TICK);

// --------------------------------------------------
// fake_crafting_table_trap.js
// --------------------------------------------------
world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const block = ev.block;
  if (block.typeId !== "ka_troll:fake_crafting_table") return;

  const { x, y, z } = block.location;
  const prob = Math.random();

  system.run(() => {
    ev.player.runCommandAsync(`setblock ${x} ${y} ${z} minecraft:air`);

    if (prob < 0.03) {
      ev.player.runCommandAsync(`summon minecraft:creeper ${x} ${y + 1} ${z}`);
      system.runTimeout(() => {
        ev.player.runCommandAsync(
          `setblock ${x} ${y} ${z} ka_troll:fake_crafting_table`
        );
      }, 1);
    } else {
      // nada extra
    }
  });
});

// --------------------------------------------------
// interactive_storm_item.js
// --------------------------------------------------
if (!STATE.stormTrapBlocks) STATE.stormTrapBlocks = {};
const STORM_COOLDOWN_TICKS = 20;
const lastStormTime = new Map();

world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const item = ev.itemStack;
  const block = ev.block;
  if (item?.typeId !== "ka_troll:interactive_storm_item") return;

  system.run(() => {
    const k = `${block.location.x},${block.location.y},${block.location.z}`;
    STATE.stormTrapBlocks[k] = block.typeId;
    saveTrapState();
  });
});

system.runInterval(() => {
  const map = STATE.stormTrapBlocks;
  world.getPlayers().forEach((player) => {
    const pLoc = player.location;
    const below = {
      x: Math.floor(pLoc.x),
      y: Math.floor(pLoc.y - 0.4),
      z: Math.floor(pLoc.z),
    };
    const key = `${below.x},${below.y},${below.z}`;
    const typeId = map[key];
    if (!typeId) return;

    const block = player.dimension.getBlock(below);
    if (!block || block.typeId !== typeId) return;

    const now = system.currentTick;
    const last = lastStormTime.get(player.id) ?? -999999;
    if (now - last < STORM_COOLDOWN_TICKS) return;
    lastStormTime.set(player.id, now);

    player.runCommandAsync(
      `summon lightning_bolt ${below.x} ${below.y} ${below.z}`
    );
    player.runCommandAsync(`weather thunder 60`);
    player.runCommandAsync(
      `playsound ambient.weather.thunder @s ${below.x} ${below.y} ${below.z}`
    );

    delete map[key];
    saveTrapState();
  });
}, 1);

// --------------------------------------------------
// blindness_item_inventory.js
// --------------------------------------------------
const BLIND_ITEM = "ka_troll:blindness_item";
const CHECK_INTERVAL_TICKS = 10;
const TRIGGER_CHANCE = 0.06;
const COOLDOWN_TICKS = 20 * 15;

const lastBlindTime = new Map();

system.runInterval(() => {
  const now = system.currentTick;

  for (const player of world.getPlayers()) {
    const inv = player.getComponent("minecraft:inventory")?.container;
    if (!inv) continue;

    let hasItem = false;
    for (let i = 0; i < inv.size; i++) {
      const item = inv.getItem(i);
      if (item?.typeId === BLIND_ITEM) {
        hasItem = true;
        break;
      }
    }

    if (!hasItem) continue;

    const last = lastBlindTime.get(player.id) ?? -999999;
    if (now - last < COOLDOWN_TICKS) continue;

    if (Math.random() < TRIGGER_CHANCE) {
      player.runCommandAsync(`effect @s blindness 20 1 true`);
      lastBlindTime.set(player.id, now);
    }
  }
}, CHECK_INTERVAL_TICKS);

// --------------------------------------------------
// fake_sounds_trap.js
// --------------------------------------------------
if (!STATE.fakeSoundBlocks) STATE.fakeSoundBlocks = {};

world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const item = ev.itemStack;
  const block = ev.block;
  if (item?.typeId !== "ka_troll:fake_sounds") return;

  system.run(() => {
    const key = `${block.location.x},${block.location.y},${block.location.z}`;
    STATE.fakeSoundBlocks[key] = block.typeId;
    saveTrapState();
  });
});

system.runInterval(() => {
  const map = STATE.fakeSoundBlocks;
  for (const player of world.getPlayers()) {
    const loc = player.location;
    const below = {
      x: Math.floor(loc.x),
      y: Math.floor(loc.y - 0.4),
      z: Math.floor(loc.z),
    };
    const key = `${below.x},${below.y},${below.z}`;
    if (!map[key]) continue;

    const block = player.dimension.getBlock(below);
    if (!block || block.typeId !== map[key]) continue;

    const pool = [
      "step.stone",
      "step.grass",
      "portal.portal",
      "portal.travel",
      "random.fuse",
    ];

    if (Math.random() < 0.7) {
      const n = 1 + Math.floor(Math.random() * 2);
      for (let i = 0; i < n; i++) {
        const s = pool[Math.floor(Math.random() * pool.length)];
        const vol = (Math.random() * 0.8 + 0.8).toFixed(2);
        const pit = (Math.random() * 0.6 + 0.7).toFixed(2);
        player.runCommandAsync(
          `playsound ${s} @a ${below.x} ${below.y} ${below.z} ${vol} ${pit}`
        );
      }
    } else {
      const fallback = ["random.orb", "random.pop", "random.door_open"];
      const s = fallback[Math.floor(Math.random() * fallback.length)];
      player.runCommandAsync(
        `playsound ${s} @a ${below.x} ${below.y} ${below.z}`
      );
    }
  }
}, 5);

// --------------------------------------------------
// speed_floor_trap.js
// --------------------------------------------------
if (!STATE.speedFloorBlocks) STATE.speedFloorBlocks = {};
const SPEED_ITEM_ID = "ka_troll:speed_floor";
const SPEED_DURATION_SECONDS = 5;

const SPEED_CHECK_INTERVAL = 1;
const SPEED_COOLDOWN_TICKS = 20 * 2;

const lastSpeedTime = new Map();

world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const item = ev.itemStack;
  const block = ev.block;
  if (item?.typeId !== SPEED_ITEM_ID) return;

  system.run(() => {
    const key = `${block.location.x},${block.location.y},${block.location.z}`;
    STATE.speedFloorBlocks[key] = block.typeId;
    saveTrapState();
  });
});

system.runInterval(() => {
  const map = STATE.speedFloorBlocks;
  const now = system.currentTick;

  for (const player of world.getPlayers()) {
    const loc = player.location;
    const below = {
      x: Math.floor(loc.x),
      y: Math.floor(loc.y - 0.4),
      z: Math.floor(loc.z),
    };
    const key = `${below.x},${below.y},${below.z}`;
    const typeId = map[key];
    if (!typeId) continue;

    const block = player.dimension.getBlock(below);
    if (!block || block.typeId !== typeId) continue;

    const last = lastSpeedTime.get(player.id) ?? -999999;
    if (now - last < SPEED_COOLDOWN_TICKS) continue;

    player.runCommandAsync(
      `effect @s speed ${SPEED_DURATION_SECONDS} 255 true`
    );
    lastSpeedTime.set(player.id, now);
  }
}, SPEED_CHECK_INTERVAL);

// --------------------------------------------------
// chameleon_block_trap.js
// --------------------------------------------------
if (!STATE.chameleonBlocks) STATE.chameleonBlocks = {};

const CHAM_ITEM_ID = "ka_troll:chameleon_block";
const CHAM_CHECK_INTERVAL = 1;
const CHAM_ROTATE_TICKS = 4;

const CHAM_BLOCKS = [
  "minecraft:dirt",
  "minecraft:stone",
  "minecraft:deepslate",
  "minecraft:sand",
];

const BLOCKS_PROHIBIDOS = ["minecraft:bedrock", "minecraft:barrier"];

world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const item = ev.itemStack;
  const block = ev.block;

  if (item?.typeId !== CHAM_ITEM_ID) return;

  if (BLOCKS_PROHIBIDOS.includes(block.typeId)) return;

  system.run(() => {
    const key = `${block.location.x},${block.location.y},${block.location.z}`;
    STATE.chameleonBlocks[key] = {
      type: block.typeId,
      idx: 0,
      active: false,
      nextAt: 0,
    };
    saveTrapState();
  });
});

system.runInterval(() => {
  const map = STATE.chameleonBlocks;
  const now = system.currentTick;

  for (const [key, data] of Object.entries(map)) {
    const [x, y, z] = key.split(",").map(Number);
    const loc = { x, y, z };

    if (!data.active) {
      for (const p of world.getPlayers()) {
        const pl = p.location;
        const below = {
          x: Math.floor(pl.x),
          y: Math.floor(pl.y - 0.4),
          z: Math.floor(pl.z),
        };

        if (below.x === x && below.y === y && below.z === z) {
          data.active = true;
          data.nextAt = now;
          break;
        }
      }
    }

    if (data.active && now >= data.nextAt) {
      const nextId = CHAM_BLOCKS[data.idx % CHAM_BLOCKS.length];
      _changeBlock(loc, nextId);
      data.idx++;
      data.nextAt = now + CHAM_ROTATE_TICKS;
    }
  }
}, CHAM_CHECK_INTERVAL);

// --------------------------------------------------
// chicken_stick_spawner.js
// --------------------------------------------------
const CHICKEN_STICK_ID = "ka_troll:chicken_stick";
const CHICKEN_SPAWN_INTERVAL = 5;
const lastChickenSpawn = new Map();

system.runInterval(() => {
  const now = system.currentTick;

  for (const player of world.getPlayers()) {
    const mainhand = player
      .getComponent("equippable")
      ?.getEquipment("Mainhand");
    if (mainhand?.typeId !== CHICKEN_STICK_ID) continue;

    const last = lastChickenSpawn.get(player.id) ?? -999999;
    if (now - last < CHICKEN_SPAWN_INTERVAL) continue;

    const p = player.location;
    player.dimension.spawnEntity("minecraft:chicken", {
      x: p.x + (Math.random() - 0.5) * 1.5,
      y: p.y,
      z: p.z + (Math.random() - 0.5) * 1.5,
    });

    lastChickenSpawn.set(player.id, now);
  }
}, 1);

// --------------------------------------------------
// falling_block_trap.js
// --------------------------------------------------
if (!STATE.fallingBlocks) STATE.fallingBlocks = {};

const FALLING_ITEM_ID = "ka_troll:falling_block";
const FALLING_CHECK_INTERVAL = 1;
const FALLING_COOLDOWN_TICKS = 20 * 3;
const lastFallTp = new Map();

world.beforeEvents.playerInteractWithBlock.subscribe((ev) => {
  const item = ev.itemStack;
  const block = ev.block;
  if (item?.typeId !== FALLING_ITEM_ID) return;

  system.run(() => {
    const key = `${block.location.x},${block.location.y},${block.location.z}`;
    STATE.fallingBlocks[key] = block.typeId;
    saveTrapState();
  });
});

system.runInterval(() => {
  const map = STATE.fallingBlocks;
  const now = system.currentTick;

  for (const player of world.getPlayers()) {
    const loc = player.location;
    const below = {
      x: Math.floor(loc.x),
      y: Math.floor(loc.y - 0.4),
      z: Math.floor(loc.z),
    };
    const key = `${below.x},${below.y},${below.z}`;
    const typeId = map[key];
    if (!typeId) continue;

    const block = player.dimension.getBlock(below);
    if (!block || block.typeId !== typeId) continue;

    const last = lastFallTp.get(player.id) ?? -999999;
    if (now - last < FALLING_COOLDOWN_TICKS) continue;

    player.teleport(
      { x: loc.x, y: loc.y + 100, z: loc.z },
      { dimension: player.dimension, rotation: player.getRotation() }
    );

    player.runCommandAsync(
      `playsound mob.ghast.scream @s ${loc.x} ${loc.y} ${loc.z}`
    );

    lastFallTp.set(player.id, now);
  }
}, FALLING_CHECK_INTERVAL);

// --------------------------------------------------
// KA BOOK
// --------------------------------------------------
const teamName = "Ka Studios";
const addonName = "44 Ways To Prank Add-On";
const guideBookStructure = "ka_troll_book:ka_troll_book";
const BOOK_GIVEN_TAG = "ka_troll_book_given";

world.afterEvents.playerSpawn.subscribe((event) => {
  const { player, initialSpawn } = event;

  if (player.hasTag(BOOK_GIVEN_TAG)) return;
  if (initialSpawn === false) return;

  player.runCommandAsync(`structure load ${guideBookStructure} ~~~`);
  player.runCommandAsync(
    `tellraw @a {"rawtext":[{"text":"§e${addonName} Guide Book has been provided by ${teamName}"}]}`
  );
  player.addTag(BOOK_GIVEN_TAG);
});
