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

const SEARCH_RADIUS = 128;
const SMOOTH_STEP = 0.25;
const FOLLOW_INTERVAL = 1.5; // ticks
const STUCK_THRESHOLD_TICKS = 50; // 2.5 segundos
const NO_HIT_TIMEOUT = 10 * 20; // 10 segundos en ticks
const knownToxicBalls = new Set();
const lastPositions = new Map();      // entity.id → last location
const stuckTimers = new Map();        // entity.id → stuck time
const lastHitTimers = new Map();      // entity.id → ticks desde último hit
const DIMENSION_IDS = ["overworld", "nether", "the_end"];

const SPAWN_SPIDER_INTERVAL = 15 * 20; // 15 segundos en ticks
const spiderSpawnTimers = new Map(); // entity.id → ticks desde última invocación

const SPIDER_TYPES = [
  "dungeon:green_lynx",
  "dungeon:cavern_spider",
  "dungeon:funnel_spider"
];
function getDistance(pos1, pos2) {
  const dx = pos1.x - pos2.x;
  const dy = pos1.y - pos2.y;
  const dz = pos1.z - pos2.z;
  return Math.sqrt(dx * dx + dy * dy + dz * dz);
}

function getNearestPlayer(entity) {
  const players = entity.dimension.getPlayers({
    location: entity.location,
    maxDistance: SEARCH_RADIUS
  });

  if (players.length === 0) return null;

  players.sort((a, b) => getDistance(a.location, entity.location) - getDistance(b.location, entity.location));
  return players[0];
}

function isTrapped(entity) {
  const loc = entity.location;

  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 }
  ];

  for (const d of directions) {
    const block = entity.dimension.getBlock({
      x: Math.floor(loc.x + d.x),
      y: Math.floor(loc.y + d.y),
      z: Math.floor(loc.z + d.z)
    });
    if (block && block.isAir) return false;
  }

  return true;
}

// Reinicia el contador de no-hit cuando daña a un jugador
world.afterEvents.entityHurt.subscribe(({ damageSource, hurtEntity }) => {
  if (!damageSource.damagingEntity || hurtEntity.typeId !== "minecraft:player") return;
  const attacker = damageSource.damagingEntity;
  if (attacker.typeId === "dungeon:spider_boss") {
    lastHitTimers.set(attacker.id, 0);
  }
});

system.runInterval(() => {
  for (const dimId of DIMENSION_IDS) {
    const dimension = world.getDimension(dimId);
    const entities = dimension
      .getEntities({ families: ["spider_boss"] })
      .filter(e => !e.hasTag("spider_minion"));


    for (const entity of entities) {

      // Si tiene la etiqueta "event_fear_spider" y no ha usado el efecto antes
      if (entity.hasTag("event_fear_spider") && !entity.hasTag("fear_used")) {
        try {
          // Ejecutar animación de miedo
          entity.runCommand("playanimation @s animation.dspiderboss.evoke_fear");
          entity.runCommand("effect @s slowness 2 255 true");

          // Sonido inmediato
          entity.runCommand("playsound fear.spider_boss @a[r=64]");

          // Marcar que ya se usó el efecto
          entity.addTag("fear_used");
          entity.removeTag("event_fear_spider");

          // Ejecutar efecto de insomnio después de 2.5 segundos (50 ticks)
          system.runTimeout(() => {
            try {
              entity.runCommand(`execute as @a[r=64,m=0,scores={insomnio=0..300000}] run scoreboard players add @s insomnio 500000`);
            } catch (e) { }
          }, 50);

        } catch (e) { }
      }


      // Buscar toxic_balls cercanas
      const nearbyToxicBalls = entity.dimension.getEntities({
        type: "dungeon:toxic_ball",
        location: entity.location,
        maxDistance: 3
      });

      for (const ball of nearbyToxicBalls) {
        if (!knownToxicBalls.has(ball.id)) {
          knownToxicBalls.add(ball.id);

          try {
            entity.runCommand("playanimation @s animation.dspiderboss.ranged_attack");
          } catch (e) { }
        }
      }

      const player = getNearestPlayer(entity);
      if (!player) continue;

      const id = entity.id;
      const currentPos = entity.location;
      const lastPos = lastPositions.get(id);
      const stuckTicks = stuckTimers.get(id) ?? 0;
      const hitTicks = lastHitTimers.get(id) ?? 0;
      lastHitTimers.set(id, hitTicks + FOLLOW_INTERVAL);
      const spiderTimer = spiderSpawnTimers.get(id) ?? 0;
      spiderSpawnTimers.set(id, spiderTimer + FOLLOW_INTERVAL);

      // Invocar arañas al azar si no hay más de 4 cerca
      if (spiderSpawnTimers.get(id) >= SPAWN_SPIDER_INTERVAL && entity.hasTag("spider_spawn_active")) {
        spiderSpawnTimers.set(id, 0);

        const nearbySpiders = entity.dimension.getEntities({
          location: entity.location,
          maxDistance: 32,
          families: ["otherworldly_spiders"]
        });

        if (nearbySpiders.length < 4) {
          const randomType = SPIDER_TYPES[Math.floor(Math.random() * SPIDER_TYPES.length)];
          const spawnX = entity.location.x + (Math.random() - 0.5) * 6;
          const spawnZ = entity.location.z + (Math.random() - 0.5) * 6;
          const spawnY = entity.location.y + 1;

          try {
            entity.dimension.runCommand(`summon ${randomType} ${spawnX} ${spawnY} ${spawnZ} ~ ~ minecraft:entity_spawned`);
          } catch (e) { }
        }
      }

      // Inactividad ofensiva → invocar Nocturnal Shade si hay menos de 4
      if (lastHitTimers.get(id) >= NO_HIT_TIMEOUT && entity.hasTag("ghost_spawn_active")) {
        lastHitTimers.set(id, 0);

        const nearbyShades = entity.dimension.getEntities({
          type: "dungeon:nocturnal_shade",
          location: entity.location,
          maxDistance: 32 // radio razonable
        });

        if (nearbyShades.length < 6) {
          try {
            entity.dimension.runCommand(
              `summon dungeon:nocturnal_shade ${entity.location.x} ${entity.location.y + 1} ${entity.location.z} ~ ~ minecraft:event_fear_nocturnal`
            );
          } catch (e) { }
        }
      }

      // Detectar si se quedó quieta
      if (lastPos && getDistance(currentPos, lastPos) < 1.4) {
        stuckTimers.set(id, stuckTicks + FOLLOW_INTERVAL);
      } else {
        stuckTimers.set(id, 0);
        lastPositions.set(id, { ...currentPos });
      }

      if (stuckTimers.get(id) >= STUCK_THRESHOLD_TICKS) {
        stuckTimers.set(id, 0);

        for (let i = 0; i < 20; i++) {
          const offsetX = (Math.random() - 0.5) * 2;
          const offsetY = Math.random() * 1.5;
          const offsetZ = (Math.random() - 0.5) * 2;
          dimension.spawnParticle("minecraft:end_chest", {
            x: currentPos.x + offsetX,
            y: currentPos.y + offsetY,
            z: currentPos.z + offsetZ
          });
        }

        system.runTimeout(() => {
          const offsetX = (Math.random() - 0.5) * 4;
          const offsetZ = (Math.random() - 0.5) * 4;
          const safeY = Math.floor(player.location.y);

          const targetX = player.location.x + offsetX;
          const targetZ = player.location.z + offsetZ;
          const targetY = player.location.y + 1;

          const block = dimension.getBlock({ x: Math.floor(targetX), y: safeY, z: Math.floor(targetZ) });
          const blockAbove = dimension.getBlock({ x: Math.floor(targetX), y: safeY + 1, z: Math.floor(targetZ) });
          try {
            const nearbySpiders = entity.dimension.getEntities({
              location: entity.location,
              maxDistance: 32,
              families: ["spider_minion"]
            });
          
          if (nearbySpiders.length < 6) {
            try {
              entity.dimension.runCommand(`summon dungeon:spider_boss ${targetX} ${targetY} ${targetZ} ~ ~ minecraft:event_minion`);
            } catch (e) { }
          }
          } catch (e) { }

          if (block && !block.isAir && blockAbove && blockAbove.isAir) {
            entity.teleport({ x: targetX, y: safeY, z: targetZ }, { facingLocation: player.location });
          }
        }, 20);
      }

      // Subida con bloque si es necesario (sólo si el destino no es negativo)
      const diffY = player.location.y - entity.location.y;
      if (player.location.y >= 0 && Math.abs(diffY) > 0.1) {
        const step = Math.min(Math.abs(diffY), SMOOTH_STEP) * Math.sign(diffY);
        const newY = entity.location.y + step;

        const x = Math.floor(entity.location.x);
        const z = Math.floor(entity.location.z);
        const yBelow = Math.floor(newY) - 1;

        const blockBelow = dimension.getBlock({ x, y: yBelow, z });
        const blockAtY = dimension.getBlock({ x, y: Math.floor(newY), z });
        const blockAbove = dimension.getBlock({ x, y: Math.floor(newY) + 1, z });

        const isPathClear = blockAtY?.isAir && blockAbove?.isAir;

        if (isPathClear) {
          if (blockBelow && blockBelow.isAir && step > 0) {
            try {
              blockBelow.setType("dungeon:spider_nest_boss");
            } catch (e) { }
          }

          entity.teleport(
            { x: entity.location.x, y: newY, z: entity.location.z },
            { facingLocation: player.location }
          );
        }
      }

      // Traspaso de paredes si está atrapada
      if (isTrapped(entity)) {
        const offsetX = (Math.random() - 0.5) * 4;
        const offsetZ = (Math.random() - 0.5) * 4;
        const safeY = Math.floor(player.location.y);
        entity.teleport(
          { x: player.location.x + offsetX, y: safeY, z: player.location.z + offsetZ },
          { facingLocation: player.location }
        );
      }
    }
  }
}, FOLLOW_INTERVAL);
