import * as MC from "@minecraft/server";
import { run, onHitEntity, onHurtEntity, onDeathEntity } from "./utilities";

run((players) => {
  players.forEach((player) => {
    const widows = player.dimension.getEntities({
      type: "chronicoverride_llc:widow",
      location: player.location,
    });

    if (widows.length > 0) {
      widows.forEach((widow) => {
        const location = widow.location;
        const locations = [
          { x: location.x + 1, y: location.y, z: location.z },
          { x: location.x - 1, y: location.y, z: location.z },
          { x: location.x, y: location.y, z: location.z + 1 },
          { x: location.x, y: location.y, z: location.z - 1 },
        ];

        let inWebBlock;

        for (const location of locations) {
          const block = widow.dimension.getBlock(location);
          if (block?.typeId === "minecraft:web") {
            inWebBlock = true;
            break;
          }
        }

        if (inWebBlock) {
          widow.addEffect("minecraft:speed", 20, {
            amplifier: 7,
            showParticles: false,
          });
        } else {
          widow.removeEffect("minecraft:speed");
        }
      });
    }
  });
});

run((players) => {
  players.forEach((player) => {
    const watchers = player.dimension.getEntities({
      type: "chronicoverride_llc:watcher",
      location: player.location,
      maxDistance: 64,
    });

    if (watchers.length > 0) {

      watchers.forEach((watcher) => {
        const watcherPos = watcher.location;
        const watcherDir = watcher.getViewDirection();

        const playerPos = player.location;

        const dx = playerPos.x - watcherPos.x;
        const dz = playerPos.z - watcherPos.z;
        const distanceSq = dx * dx + dz * dz;

        if (distanceSq > 4096) return;

        const len1 = Math.sqrt(dx * dx + dz * dz);
        const dirToPlayer = { x: dx / len1, z: dz / len1 };

        const dotWatcherToPlayer =
          watcherDir.x * dirToPlayer.x + watcherDir.z * dirToPlayer.z;

        if (dotWatcherToPlayer < 0.5) return;

        const playerDir = player.getViewDirection();
        const dx2 = watcherPos.x - playerPos.x;
        const dz2 = watcherPos.z - playerPos.z;

        const len2 = Math.sqrt(dx2 * dx2 + dz2 * dz2);
        const dirToWatcher = { x: dx2 / len2, z: dz2 / len2 };

        const dotPlayerToWatcher =
          playerDir.x * dirToWatcher.x + playerDir.z * dirToWatcher.z;
        if (dotPlayerToWatcher < 0.5) return;

        if (!watcher.getProperty("chronicoverride_llc:is_stunned"))
          player.runCommand(`effect @s slowness 1 2 false`);
      });
    }
  });
});

run((players) => {
  players.forEach((player) => {
    const facelesses = player.dimension.getEntities({
      type: "chronicoverride_llc:faceless",
      location: player.location,
      maxDistance: 32
    });

    if (facelesses.length > 0) {
      facelesses.forEach((faceless) => {
        const lightBlocks = [
          "minecraft:torch",
          "minecraft:lantern",
          "minecraft:glowstone",
          "minecraft:sea_lantern",
          "minecraft:campfire",
          "minecraft:shroomlight",
          "minecraft:light_block",
          "minecraft:lit_redstone_lamp",
          "minecraft:lit_pumpkin",
          "minecraft:ochre_froglight",
          "minecraft:pearlescent_froglight",
          "minecraft:verdant_froglight",
          "minecraft:light_block_6",
          "minecraft:light_block_7",
          "minecraft:light_block_8",
          "minecraft:light_block_9",
          "minecraft:light_block_10",
          "minecraft:light_block_11",
          "minecraft:light_block_12",
          "minecraft:light_block_13",
          "minecraft:light_block_14",
          "minecraft:light_block_15",
          "chronicoverride_llc:shade_candle",
        ];

        const facelessPos = faceless.location;
        const radius = 8; // Rayon de recherche (par exemple)

        // Point le plus bas et le plus à l'ouest/nord
        const min = {
          x: Math.floor(facelessPos.x) - radius,
          y: Math.floor(facelessPos.y) - radius,
          z: Math.floor(facelessPos.z) - radius
        };

        // Point le plus haut et le plus à l'est/sud
        const max = {
          x: Math.floor(facelessPos.x) + radius,
          y: Math.floor(facelessPos.y) + radius,
          z: Math.floor(facelessPos.z) + radius
        };

        const blockVolume = new MC.BlockVolume(min, max);
        const filter = {
          includeTypes: lightBlocks
        }

        const foundBlocks = faceless.dimension.getBlocks(blockVolume,
          filter
        );

        // No blocks found => do nothing
        if (foundBlocks.length <= 0) {
          return;
        }

        let lightSourcePos = undefined;
        for (const location of foundBlocks.getBlockLocationIterator()) {
          lightSourcePos = location;
          break;
        }

        if (!lightSourcePos) {
          return;
        }

        // Teleport outside the light radius
        const dx = facelessPos.x - lightSourcePos.x;
        const dz = facelessPos.z - lightSourcePos.z;
        const distance = Math.sqrt(dx * dx + dz * dz);

        if (distance > 0) {
          const dirX = dx / distance;
          const dirZ = dz / distance;

          const teleportDistance = 24;
          const newX = lightSourcePos.x - dirX * teleportDistance;
          const newZ = lightSourcePos.z - dirZ * teleportDistance;

          let newY = facelessPos.y;
          for (let yOffset = 0; yOffset <= 5; yOffset++) {
            const testY = Math.floor(facelessPos.y) + yOffset;
            try {
              const blockBelow = faceless.dimension.getBlock({
                x: Math.floor(newX),
                y: testY - 1,
                z: Math.floor(newZ),
              });
              const blockAt = faceless.dimension.getBlock({
                x: Math.floor(newX),
                y: testY,
                z: Math.floor(newZ),
              });
              const blockAbove = faceless.dimension.getBlock({
                x: Math.floor(newX),
                y: testY + 1,
                z: Math.floor(newZ),
              });

              if (
                blockBelow &&
                !blockBelow.isAir &&
                blockAt &&
                blockAt.isAir &&
                blockAbove &&
                blockAbove.isAir
              ) {
                newY = testY;
                break;
              }
            } catch (error) {
              continue;
            }
          }

          try {
            faceless.runCommand(`playsound mob.endermen.scream @a[r=10]`);
            faceless.runCommand(
              `particle chronicoverride_llc:faceless_particle ~~~`
            );
            faceless.teleport({
              x: newX,
              y: newY,
              z: newZ,
            });
          } catch (error) {
            const randomAngle = Math.random() * 2 * Math.PI;
            const randomX = facelessPos.x + Math.cos(randomAngle) * 12;
            const randomZ = facelessPos.z + Math.sin(randomAngle) * 12;

            try {
              faceless.teleport({
                x: randomX,
                y: facelessPos.y,
                z: randomZ,
              });
            } catch (fallbackError) { }
          }
        }
      });
    }
  })
});

onHitEntity(({ damagingEntity, hitEntity }) => {
  if (damagingEntity.typeId === "chronicoverride_llc:lurker") {
    damagingEntity.runCommand(
      `event entity @s chronicoverride_llc:avoid_state`
    );
  }

  if (damagingEntity.typeId === "chronicoverride_llc:faceless") {
    hitEntity.runCommand(`playsound sas.faceless.attack @s`);
  }
  if (
    hitEntity.typeId === "chronicoverride_llc:faceless" &&
    !hitEntity.getProperty("chronicoverride_llc:is_stunned")
  ) {
    hitEntity.runCommand(`playsound mob.endermen.scream @a[r=10]`);
    hitEntity.runCommand(`particle chronicoverride_llc:faceless_particle ~~~`);

    const playerLocation = damagingEntity.location;
    const playerDirection = damagingEntity.getViewDirection();

    const behindDistance = 1;
    const behindX = playerLocation.x - playerDirection.x * behindDistance;
    const behindY = playerLocation.y;
    const behindZ = playerLocation.z - playerDirection.z * behindDistance;

    const teleported = hitEntity.tryTeleport({
      x: behindX,
      y: behindY,
      z: behindZ,
    });

    if (!teleported) {
      hitEntity.teleport(playerLocation);
    }
  }

  if (damagingEntity.typeId === "chronicoverride_llc:whisper") {
    hitEntity.runCommand(`effect @s nausea 8 0 true`);
    hitEntity.runCommand(`effect @s slowness 3 2 true`);
  }
  if (damagingEntity.typeId === "chronicoverride_llc:night_stalker") {
    hitEntity.runCommand(`playsound sas.nightstalker.attack @s`);
    hitEntity.runCommand(`camera @s fade time 1.5 0 1.5 color 255 255 255`);
    MC.system.runTimeout(() => {
      hitEntity.runCommand(`damage @s 1`);
    }, 10);
    MC.system.runTimeout(() => {
      hitEntity.runCommand(`damage @s 1`);
    }, 15);
    MC.system.runTimeout(() => {
      hitEntity.runCommand(`damage @s 1`);
    }, 20);
    MC.system.runTimeout(() => {
      hitEntity.runCommand(`damage @s 1`);
    }, 25);
    MC.system.runTimeout(() => {
      hitEntity.runCommand(`damage @s 1`);
    }, 30);
  }
  if (damagingEntity.typeId === "chronicoverride_llc:shadewalker") {
    damagingEntity.runCommand(`playsound block.end_portal.spawn @a[r=8]`);
    damagingEntity.runCommand(
      `particle chronicoverride_llc:shadewalker_particle ~~0.5~`
    );
    hitEntity.runCommand(`effect @s darkness 8 0 true`);
    hitEntity.runCommand(`effect @s blindness 8 0 true`);
  }
  if (damagingEntity.typeId === "chronicoverride_llc:widow") {
    hitEntity.runCommand(`effect @s fatal_poison 5 0 true`);
  }
  if (
    damagingEntity.typeId === "minecraft:player" &&
    hitEntity.typeId === "chronicoverride_llc:widow"
  ) {
    hitEntity.runCommand(`event entity @s chronicoverride_llc:avoid_state`);
  }
});

onHurtEntity(({ damageSource, hurtEntity }) => {

  // Ensure the hurt entity is a Widow
  if (hurtEntity.typeId != "chronicoverride_llc:widow") {
    return;
  }

  // Check if the damage source is fire or a sword
  const item = damageSource.damagingEntity
    ?.getComponent("minecraft:equippable")
    ?.getEquipmentSlot("Mainhand")
    ?.getItem();

  if (damageSource.cause === "fire" || item?.hasTag("minecraft:is_sword")) {
    hurtEntity.triggerEvent("chronicoverride_llc:avoid_state");
  }
});

MC.world.afterEvents.entitySpawn.subscribe(({ cause, entity }) => {
  // Only process natural spawns and entity must exist
  if (cause != "Spawned" || !entity || !entity.isValid) {
    return;
  }

  if (!entity.typeId.startsWith("chronicoverride")) {
    return;
  }

  // Ensure the entity family component can be accessed
  if (!entity.hasComponent("minecraft:type_family")) {
    return;
  }

  // Ensure the entity is part of the monster family
  const familyComponent = entity.getComponent("minecraft:type_family");
  if (!familyComponent.hasTypeFamily("monster")) {
    return;
  }

  const isDreamcatcherNearby = entity.dimension.getEntities({
    type: "chronicoverride_llc:dreamcatcher",
    location: entity.location,
    maxDistance: 24,
    closest: 1,
  }).length > 0;

  if (isDreamcatcherNearby) {
    entity.remove();
  }
});

MC.world.afterEvents.projectileHitEntity.subscribe((event) => {
  const { projectile } = event;
  if (projectile.typeId === "chronicoverride_llc:widow_web_proj") {
    const target = event.getEntityHit().entity;
    if (target.typeId === "minecraft:player") {
      target.runCommand(`fill ~1~~1 ~-1~~-1 web replace air`);
    }
  }
  if (projectile.typeId === "chronicoverride_llc:screecher_proj") {
    const target = event.getEntityHit().entity;
    if (target.typeId === "minecraft:player") {
      target.runCommand(`effect @s nausea 10 0 true`);
      target.runCommand(`camera @s fade time 1.5 0 1.5 color 0 0 0`);
    }
  }
});

MC.world.afterEvents.projectileHitBlock.subscribe((event) => {
  const { projectile, source } = event;
  if (projectile.typeId === "chronicoverride_llc:boulder") {
    source.triggerEvent("chronicoverride_llc:angry_state");
  }
});
