import * as mc from "@minecraft/server";
import * as vector from "../utils/vector";
import * as scul from "./sculptor";

function constrain(number, min, max) {
  if (number < min) return min;
  if (number > max) return max;
  return number;
}

export const BoulderTypes = [
  "dirt",
  "gravel",
  "stone",
  "cobblestone",
  "diorite",
  "andesite",
  "granite",
  "deepslate",
  "cobbled_deepslate",
  "tuff",
  "dripstone",
  "clay",
  "sandstone",
  "red_sandstone",
];

export function launchBoulder(event) {
  const { damagingEntity, hitEntity } = event;

  if (damagingEntity.typeId === "minecraft:player" && hitEntity.typeId === "hf_mzs:boulder") {
    const mainHand = damagingEntity.getComponent("equippable").getEquipment(mc.EquipmentSlot.Mainhand);
    if (
      mainHand &&
      mainHand.typeId === "hf_mzs:earthrend_gauntlet" &&
      hitEntity.getProperty("hf_mzs:spawned") &&
      hitEntity.getProperty("hf_mzs:can_launch")
    ) {
      let force = damagingEntity.getViewDirection();
      damagingEntity.playAnimation("animation.hf_mzs.earthrend_gauntlet.hit_boulder", {
        stopExpression: "v.is_first_person",
      });

      let map = new mc.MolangVariableMap();
      let rot = (Math.atan2(force.x, force.z) * -180) / Math.PI;
      map.setFloat("variable.direction", rot);
      map.setFloat("variable.lifetime", 0.3);
      let offset = 0.75;

      let markVariant = hitEntity.getComponent("minecraft:mark_variant");
      switch (markVariant.value) {
        case 0:
          map.setFloat("variable.size", 0.4);
          offset = 0.5;
          damagingEntity.dimension.playSound("hf_mzs:boulder.small.hit", damagingEntity.location, {
            volume: 0.5,
            pitch: 1.0,
          });
          break;
        case 1:
          map.setFloat("variable.size", 0.6);
          damagingEntity.dimension.playSound("hf_mzs:boulder.medium.hit", damagingEntity.location, {
            volume: 0.5,
            pitch: 0.85,
          });
          break;
        case 2:
          map.setFloat("variable.size", 0.8);
          damagingEntity.runCommand("/camerashake add @a[r=32] 0.5 0.25 positional");
          damagingEntity.dimension.playSound("hf_mzs:boulder.large.hit", damagingEntity.location, {
            volume: 0.5,
            pitch: 0.8,
          });
          break;
        case 3:
          map.setFloat("variable.size", 1.0);
          damagingEntity.runCommand("/camerashake add @a[r=32] 0.75 0.25 positional");
          damagingEntity.dimension.playSound("hf_mzs:boulder.giant.hit", damagingEntity.location, {
            volume: 0.5,
            pitch: 0.7,
          });
          break;
      }

      fillBlocks(hitEntity, markVariant.value, true);

      force = vector.multiply(force, 0.25);

      if (entityIsOnBoulder(damagingEntity, hitEntity)) {
        force.x *= 2;
        force.y = 0;
        force.z *= 2;
        let id = `${hitEntity.id}`;
        damagingEntity.addTag(id);
        mc.system.runTimeout(() => {
          damagingEntity.removeTag(id);
        }, 20);
      }

      let particleLocation = vector.subtract(hitEntity.location, vector.multiply(force, 3));
      particleLocation.y += offset;
      damagingEntity.dimension.spawnParticle("hf_mzs:ring_grow", particleLocation, map);
      hitEntity.triggerEvent("hf_mzs:flying");
      hitEntity.setProperty("hf_mzs:launched", true);

      let boulders = hitEntity.dimension.getEntities({
        location: hitEntity.location,
        maxDistance: 2,
        type: "hf_mzs:boulder",
      });
      if (boulders.length > 1) {
        for (let b of boulders) {
          if (!b.getProperty("hf_mzs:launched")) {
            const markVariant = b.getComponent("minecraft:mark_variant");
            fillBlocks(b, markVariant.value, true);
            shootBoulder(b, force);
          }
        }
        hitEntity.triggerEvent("hf_mzs:on_hit");
      } else {
        shootBoulder(hitEntity, force);
      }
    } else if (
      (!mainHand || mainHand.typeId !== "hf_mzs:earthrend_gauntlet") &&
      hitEntity.getDynamicProperty("hf_mzs:owner") === damagingEntity.id
    ) {
      //mc.world.sendMessage("h2");
      hitEntity.triggerEvent("hf_mzs:on_hit");
    } else if (
      (!mainHand || mainHand.typeId !== "hf_mzs:earthrend_gauntlet") &&
      hitEntity.getProperty("hf_mzs:from_armor")
    ) {
      //mc.world.sendMessage("h2");
      hitEntity.triggerEvent("hf_mzs:on_hit");
    }
  }
}

export function shootBoulder(boulder, force) {
  if (boulder && boulder.isValid()) {
    if (
      boulder.location.y > boulder.dimension.heightRange.min &&
      boulder.location.y < boulder.dimension.heightRange.max
    ) {
      let bl = boulder.dimension.getBlockFromRay(boulder.location, force, {
        maxDistance: 1,
        includePassableBlocks: false,
        includeLiquidBlocks: false,
      });

      if (bl) {
        onBoulderDestroy(boulder, boulder.location);
        return;
      }

      const projectileComponent = boulder.getComponent("minecraft:projectile");
      if (projectileComponent) {
        boulder.setDynamicProperty("hf_mzs:flying_force", `${force.x},${force.y},${force.z}`);
        projectileComponent.shoot(force);
        mc.system.runTimeout(() => {
          shootBoulder(boulder, force);
        }, 1);
      }
    }
  }
  try {
  } catch (e) {}
}

function boulderCollision(boulder, force) {
  try {
    let map = new mc.MolangVariableMap();
    let rot = (Math.atan2(force.x, force.z) * -180) / Math.PI;
    map.setFloat("variable.direction", rot);
    map.setFloat("variable.lifetime", 0.5);
    let offset = 0.75;

    let markVariant = boulder.getComponent("minecraft:mark_variant");
    switch (markVariant.value) {
      case 0:
        map.setFloat("variable.size", 0.4);
        offset = 0.5;
        boulder.dimension.playSound("hf_mzs:boulder.small.hit", boulder.location, { volume: 0.5, pitch: 1.0 });
        // boulder.dimension.playSound("hf_mzs:magic_hit", boulder.location, { volume: 0.1, pitch: 0.85 });
        break;
      case 1:
        map.setFloat("variable.size", 0.6);
        boulder.dimension.playSound("hf_mzs:boulder.medium.hit", boulder.location, { volume: 0.5, pitch: 0.85 });
        // boulder.dimension.playSound("hf_mzs:magic_hit", boulder.location, { volume: 0.1, pitch: 0.8 });
        break;
      case 2:
        map.setFloat("variable.size", 0.8);
        boulder.runCommand("/camerashake add @a[r=32] 0.5 0.25 positional");
        boulder.dimension.playSound("hf_mzs:boulder.large.hit", boulder.location, { volume: 0.5, pitch: 0.8 });
        // boulder.dimension.playSound("hf_mzs:magic_hit", boulder.location, { volume: 0.1, pitch: 0.7 });
        break;
      case 3:
        map.setFloat("variable.size", 1.0);
        boulder.runCommand("/camerashake add @a[r=32] 0.75 0.25 positional");
        boulder.dimension.playSound("hf_mzs:boulder.giant.hit", boulder.location, { volume: 0.5, pitch: 0.7 });
        // boulder.dimension.playSound("hf_mzs:magic_hit", boulder.location, { volume: 0.1, pitch: 0.6 });
        break;
    }

    fillBlocks(boulder, markVariant.value, true);

    force.x /= 4;
    force.y /= 4;
    force.z /= 4;
    let particleLocation = vector.subtract(boulder.location, vector.multiply(force, 3));
    particleLocation.y += offset;
    boulder.dimension.spawnParticle("hf_mzs:ring_grow", particleLocation, map);
    boulder.triggerEvent("hf_mzs:flying");
    boulder.setProperty("hf_mzs:launched", true);
    shootBoulder(boulder, force);
  } catch (e) {}
}

export function boulderHit(event) {
  try {
    const { projectile, location } = event;
    if (
      projectile &&
      projectile.isValid() &&
      projectile.typeId === "hf_mzs:boulder" &&
      projectile.getProperty("hf_mzs:launched")
    ) {
      const hitBlock = projectile.dimension.getBlock(location);
      if (hitBlock && excludedBlocks.includes(hitBlock.typeId)) {
        return;
      }
      onBoulderDestroy(projectile, location);
    }
  } catch (e) {}
}

export function boulderDestroy(event) {
  //mc.world.sendMessage("h");
  try {
    const id = event.id;
    const projectile = event.sourceEntity;
    const location = projectile.location;
    if (id === "hf_mzs:boulder_destroy") {
      let map = new mc.MolangVariableMap();

      let markVariant = projectile.getComponent("minecraft:mark_variant");
      switch (markVariant.value) {
        case 0:
          projectile.runCommand("/playsound hf_mzs:boulder.small.hit @a[r=32] ~ ~ ~ 100 1 1");
          projectile.runCommand("/playsound hf_mzs:boulder.small.break @a[r=32] ~ ~ ~ 100 1 1");
          map.setFloat("variable.count", 25);
          break;
        case 1:
          projectile.runCommand("/playsound hf_mzs:boulder.medium.hit @a[r=32] ~ ~ ~ 100 1 1");
          projectile.runCommand("/playsound hf_mzs:boulder.medium.break @a[r=32] ~ ~ ~ 100 1 1");
          map.setFloat("variable.count", 50);
          break;
        case 2:
          projectile.runCommand("/playsound hf_mzs:boulder.large.hit @a[r=32] ~ ~ ~ 100 1 1");
          projectile.runCommand("/playsound hf_mzs:boulder.large.break @a[r=32] ~ ~ ~ 100 1 1");
          projectile.runCommand("/camerashake add @a[r=32] 0.5 0.25 positional");
          map.setFloat("variable.count", 75);
          break;
        case 3:
          projectile.runCommand("/playsound hf_mzs:boulder.giant.hit @a[r=32] ~ ~ ~ 100 1 1");
          projectile.runCommand("/playsound hf_mzs:boulder.giant.break @a[r=32] ~ ~ ~ 100 1 1");
          projectile.runCommand("/camerashake add @a[r=32] 0.75 0.25 positional");
          map.setFloat("variable.count", 100);
          break;
        case 4:
          projectile.runCommand("/playsound hf_mzs:boulder.small.hit @a[r=32] ~ ~ ~ 100 1 1");
          projectile.runCommand("/playsound hf_mzs:boulder.small.break @a[r=32] ~ ~ ~ 100 1 1");
          map.setFloat("variable.count", 25);
          break;
      }

      fillBlocks(projectile, markVariant.value, true);

      let variant = projectile.getComponent("minecraft:variant");
      let particleLocation = location;
      particleLocation.y += 1;

      projectile.dimension.spawnParticle(`hf_mzs:boulder_hit_${BoulderTypes[variant.value]}`, particleLocation, map);

      mc.system.runTimeout(() => {
        if (projectile.isValid()) projectile.remove();
      }, 1);
    }
  } catch (e) {}
}

export function onBoulderDestroy(projectile, location) {
  try {
    projectile.clearVelocity();
    projectile.teleport(location);

    let damage = 0;
    let radius = 2;
    let knockbackMultiplier = 0.5;

    let map = new mc.MolangVariableMap();

    let markVariant = projectile.getComponent("minecraft:mark_variant");
    switch (markVariant.value) {
      case 0:
        damage = 10;
        knockbackMultiplier = 0.5;
        projectile.runCommand("/playsound hf_mzs:boulder.small.hit @a[r=32] ~ ~ ~ 100 1 1");
        projectile.runCommand("/playsound hf_mzs:boulder.small.break @a[r=32] ~ ~ ~ 100 1 1");
        map.setFloat("variable.count", 25);
        break;
      case 1:
        damage = 13;
        radius = 3;
        knockbackMultiplier = 0.75;
        projectile.runCommand("/playsound hf_mzs:boulder.medium.hit @a[r=32] ~ ~ ~ 100 1 1");
        projectile.runCommand("/playsound hf_mzs:boulder.medium.break @a[r=32] ~ ~ ~ 100 1 1");
        map.setFloat("variable.count", 50);
        break;
      case 2:
        damage = 16;
        radius = 4;
        knockbackMultiplier = 1;
        projectile.runCommand("/playsound hf_mzs:boulder.large.hit @a[r=32] ~ ~ ~ 100 1 1");
        projectile.runCommand("/playsound hf_mzs:boulder.large.break @a[r=32] ~ ~ ~ 100 1 1");
        projectile.runCommand("/camerashake add @a[r=32] 0.5 0.25 positional");
        map.setFloat("variable.count", 75);
        break;
      case 3:
        damage = 20;
        radius = 5;
        knockbackMultiplier = 1.5;
        projectile.runCommand("/playsound hf_mzs:boulder.giant.hit @a[r=32] ~ ~ ~ 100 1 1");
        projectile.runCommand("/playsound hf_mzs:boulder.giant.break @a[r=32] ~ ~ ~ 100 1 1");
        projectile.runCommand("/camerashake add @a[r=32] 0.75 0.25 positional");
        map.setFloat("variable.count", 100);
        break;
      case 4:
        damage = 2;
        knockbackMultiplier = 0.25;
        projectile.runCommand("/playsound hf_mzs:boulder.small.hit @a[r=32] ~ ~ ~ 0.2 1 0.2");
        projectile.runCommand("/playsound hf_mzs:boulder.small.break @a[r=32] ~ ~ ~ 0.2 1 0.2");
        map.setFloat("variable.count", 25);
        break;
    }

    let entities = projectile.dimension.getEntities({
      location: projectile.location,
      maxDistance: radius,
      families: ["mob"],
    });
    let players = projectile.dimension.getEntities({
      location: projectile.location,
      maxDistance: radius,
      families: ["player"],
    });
    let boulders = projectile.dimension.getEntities({
      location: projectile.location,
      maxDistance: radius * 2,
      type: "hf_mzs:boulder",
    });
    entities.push(...players, ...boulders);

    for (const entity of entities) {
      if (entity.hasTag(projectile.id)) continue;
      let c = projectile.getDynamicProperty("hf_mzs:flying_force");
      c = c.split(",");
      const vel = vector.multiply(
        vector.normalize({ x: parseFloat(c[0]), y: parseFloat(c[1]), z: parseFloat(c[2]) }),
        knockbackMultiplier
      );
      if (entity.typeId !== "hf_mzs:sculptor" && entity.typeId !== "hf_mzs:boulder") {
        entity.applyDamage(damage);
        entity.applyKnockback(vel.x, vel.z, Math.sqrt(vel.x * vel.x + vel.z * vel.z) * 3, vel.y);
      } else if (
        entity.typeId === "hf_mzs:boulder" &&
        !entity.getProperty("hf_mzs:is_orbiting") &&
        entity.id !== projectile.id
      ) {
        mc.system.runTimeout(() => {
          boulderCollision(entity, vel);
        }, 1);
      }
    }

    let variant = projectile.getComponent("minecraft:variant");
    let particleLocation = location;
    particleLocation.y += 1;

    projectile.dimension.spawnParticle(`hf_mzs:boulder_hit_${BoulderTypes[variant.value]}`, particleLocation, map);

    mc.system.runTimeout(() => {
      if (projectile.isValid()) projectile.remove();
    }, 1);
  } catch (e) {}
}

export function spawnOrbiting(entity, spawnLocation, spawnY) {
  let targetSpawn = { x: spawnLocation.x, y: spawnY, z: spawnLocation.z };

  let map = new mc.MolangVariableMap();
  map.setFloat("variable.lifetime", 0.4);
  map.setFloat("variable.size", 1.0);
  let parLoc = vector.subtract(targetSpawn, { x: 0, y: 0.9, z: 0 });

  entity.dimension.spawnParticle("hf_mzs:ring_grow_ground", parLoc, map);

  const boulder = entity.dimension.spawnEntity("hf_mzs:boulder<hf_mzs:sculptor_attack>", targetSpawn);

  const orbitCenter = entity.location;
  orbitCenter.y = spawnLocation.y;
  const radius = vector.distance(boulder.location, orbitCenter);

  boulder.setDynamicProperty("hf_mzs:orbit_center", `${orbitCenter.x},${orbitCenter.y},${orbitCenter.z}`);
  boulder.setDynamicProperty("hf_mzs:orbit_start", `${spawnLocation.x},${spawnLocation.y},${spawnLocation.z}`);
  boulder.setDynamicProperty("hf_mzs:orbit_radius", `${radius}`);
  boulder.addTag(entity.id);

  const heading = { x: spawnLocation.x - orbitCenter.x, y: spawnLocation.z - orbitCenter.z };
  boulder.setDynamicProperty("hf_mzs:orbit_angle", Math.atan2(heading.y, heading.x));
}

export function spawnPlatform(sculptor, entity, maxY, id, iteration, tryNum, initial) {
  if (sculptor.getProperty("hf_mzs:is_testing") === false) {
    return;
  }

  const maxIteration = Infinity;
  const maxTries = 100;
  const personalIteration = entity.getDynamicProperty("hf_mzs:boulder_iterations") || 0;
  if (entity.typeId === "hf_mzs:boulder") entity.setDynamicProperty("hf_mzs:boulder_iterations", personalIteration + 1);

  if (entity.typeId === "hf_mzs:boulder" && personalIteration > 5) return;
  let variant = Math.floor(Math.random() * 2);
  let size;

  let xOffset;
  let yOffset;
  let zOffset;

  let radius = 3;

  switch (variant) {
    case 0:
      size = "small";
      xOffset = Math.random() < 0.5 ? 3 : 2;
      yOffset = 2;
      zOffset = Math.random() < 0.5 ? 3 : 2;
      break;
    case 1:
      size = "medium";
      xOffset = Math.random() < 0.5 ? 3 : 3;
      yOffset = 2;
      zOffset = Math.random() < 0.5 ? 3 : 3;
      radius = 4;
      break;
  }

  if (Math.random() < 0.5) xOffset *= -1;
  if (Math.random() < 0.5) zOffset *= -1;

  let spawnLocation = entity.location;

  spawnLocation.x = Math.floor(spawnLocation.x) + 0.5 + xOffset;
  spawnLocation.y = Math.floor(spawnLocation.y) + yOffset;
  spawnLocation.z = Math.floor(spawnLocation.z) + 0.5 + zOffset;

  if (initial) {
    variant = 0;
    size = "small";
    spawnLocation = initial;
  }

  if (spawnLocation.y > maxY) spawnLocation.y = maxY;

  if (iteration === -1) {
    let c = entity.getDynamicProperty("hf_mzs:start_center");
    c = c.split(",");
    spawnLocation.x = parseFloat(c[0]) + (xOffset + 2);
    spawnLocation.y = maxY;
    spawnLocation.z = parseFloat(c[2]) + (zOffset + 2);
  }

  let testCenter, sc;

  if (initial) {
    sc = `${entity.location.x},${entity.location.y},${entity.location.z}`;
    testCenter = entity.location;
  } else {
    sc = entity.getDynamicProperty("hf_mzs:start_center");
    let c = entity.getDynamicProperty("hf_mzs:start_center");
    c = c.split(",");
    testCenter = { x: parseFloat(c[0]), y: spawnLocation.y, z: parseFloat(c[2]) };
  }

  if (testCenter.x < spawnLocation.x)
    spawnLocation.x = constrain(
      spawnLocation.x,
      testCenter.x + 2,
      testCenter.x + scul.boulderRadius(sculptor, spawnLocation.y)
    );
  else if (testCenter.x > spawnLocation.x)
    spawnLocation.x = constrain(
      spawnLocation.x,
      testCenter.x - scul.boulderRadius(sculptor, spawnLocation.y),
      testCenter.x - 2
    );
  if (testCenter.z < spawnLocation.z)
    spawnLocation.z = constrain(
      spawnLocation.z,
      testCenter.z + 2,
      testCenter.z + scul.boulderRadius(sculptor, spawnLocation.y)
    );
  else if (testCenter.z > spawnLocation.z)
    spawnLocation.z = constrain(
      spawnLocation.z,
      testCenter.z - scul.boulderRadius(sculptor, spawnLocation.y),
      testCenter.z - 2
    );

  if (!initial) {
    const boulders = entity.dimension.getEntities({
      type: "hf_mzs:boulder",
      location: spawnLocation,
      maxDistance: radius,
    });
    if (boulders.length > 0) {
      // if (tryNum <= maxTries) spawnPlatform(sculptor, entity, maxY, id, iteration, tryNum + 1);
      // else spawnPlatform(sculptor, boulders[0], maxY, id, iteration, 1);
      spawnPlatform(sculptor, boulders[0], maxY, id, iteration, 1);
      return;
    }
    if (vector.distance(testCenter, spawnLocation) < 2) {
      spawnPlatform(sculptor, entity, maxY, id, iteration, 1);
      return;
    }
  }

  let map = new mc.MolangVariableMap();
  map.setFloat("variable.lifetime", 0.4);
  map.setFloat("variable.size", 1.0);
  let parLoc = vector.subtract(spawnLocation, { x: 0, y: 0.9, z: 0 });

  entity.dimension.spawnParticle("hf_mzs:ring_grow_ground", parLoc, map);
  const boulder = entity.dimension.spawnEntity(
    `hf_mzs:boulder<hf_mzs:sculptor_test${!initial && Math.random() < 0.15 ? "_crumbling" : ""}_${size}>`,
    spawnLocation
  );
  boulder.setDynamicProperty("hf_mzs:start_center", sc);
  boulder.addTag(id);

  mc.system.runTimeout(() => {
    fillBlocks(boulder, variant);

    if (spawnLocation.y + yOffset < maxY && iteration < maxIteration) {
      spawnPlatform(sculptor, boulder, maxY, id, iteration + 1);
    } else if (spawnLocation.y + yOffset >= maxY && iteration !== -1) {
      spawnPlatform(sculptor, boulder, maxY, id, -1);
    }
  }, 5);
}

export function platformToOrbiting(sculptor) {
  const boulders = sculptor.dimension.getEntities({
    type: "hf_mzs:boulder",
    location: sculptor.location,
    tags: [sculptor.id],
    maxDistance: 65,
  });
  for (const boulder of boulders) {
    let markVariant = boulder.getComponent("minecraft:mark_variant");
    fillBlocks(boulder, markVariant, true);

    const orbitCenter = sculptor.location;
    orbitCenter.y = boulder.location.y;
    const radius = vector.distance(boulder.location, orbitCenter);

    boulder.setProperty("hf_mzs:is_orbiting", true);
    boulder.setDynamicProperty("hf_mzs:orbit_center", `${orbitCenter.x},${orbitCenter.y},${orbitCenter.z}`);
    boulder.setDynamicProperty(
      "hf_mzs:orbit_start",
      `${boulder.location.x},${boulder.location.y},${boulder.location.z}`
    );
    boulder.setDynamicProperty("hf_mzs:orbit_radius", `${radius}`);

    const heading = { x: boulder.location.x - orbitCenter.x, y: boulder.location.z - orbitCenter.z };
    boulder.setDynamicProperty("hf_mzs:orbit_angle", Math.atan2(heading.y, heading.x));
  }
}

export function fillBlocks(boulder, variant, isClearing) {
  if (variant === 4) return;
  if (!boulder.isValid()) return;
  if (!isClearing) {
    if (variant >= 0) {
      boulder.runCommand(`setblock ~ ~ ~ hf_mzs:invisible_block [] replace`);
    }
    if (variant >= 1) {
      boulder.runCommand(`setblock ~ ~ ~ hf_mzs:invisible_block [] replace`);
      boulder.runCommand(`setblock ~ ~-1 ~ hf_mzs:invisible_slab ["minecraft:facing_direction"="up"] replace`);
      boulder.runCommand(`setblock ~1 ~ ~ hf_mzs:invisible_slab ["minecraft:facing_direction"="west"] replace`);
      boulder.runCommand(`setblock ~-1 ~ ~ hf_mzs:invisible_slab ["minecraft:facing_direction"="east"] replace`);
      boulder.runCommand(`setblock ~ ~ ~1 hf_mzs:invisible_slab ["minecraft:facing_direction"="north"] replace`);
      boulder.runCommand(`setblock ~ ~ ~-1 hf_mzs:invisible_slab ["minecraft:facing_direction"="south"] replace`);
    }
    if (variant >= 2) {
      boulder.runCommand(`setblock ~ ~1 ~ hf_mzs:invisible_block [] replace`);
      boulder.runCommand(`setblock ~1 ~1 ~ hf_mzs:invisible_block [] replace`);
      boulder.runCommand(`setblock ~-1 ~1 ~ hf_mzs:invisible_block [] replace`);
      boulder.runCommand(`setblock ~ ~1 ~1 hf_mzs:invisible_block [] replace`);
      boulder.runCommand(`setblock ~ ~1 ~-1 hf_mzs:invisible_block [] replace`);
      boulder.runCommand(
        `setblock ~-1 ~1 ~-1 hf_mzs:invisible_quarter ["minecraft:cardinal_direction"="east"] replace`
      );
      boulder.runCommand(`setblock ~1 ~1 ~1 hf_mzs:invisible_quarter ["minecraft:cardinal_direction"="west"] replace`);
      boulder.runCommand(
        `setblock ~-1 ~1 ~1 hf_mzs:invisible_quarter ["minecraft:cardinal_direction"="north"] replace`
      );
      boulder.runCommand(
        `setblock ~1 ~1 ~-1 hf_mzs:invisible_quarter ["minecraft:cardinal_direction"="south"] replace`
      );
    }
    if (variant >= 3) {
      boulder.runCommand(`fill ~-1 ~2 ~-1 ~1 ~2 ~1 hf_mzs:invisible_block [] replace`);
      boulder.runCommand(`setblock ~2 ~2 ~ hf_mzs:invisible_slab ["minecraft:facing_direction"="west"] replace`);
      boulder.runCommand(`setblock ~-2 ~2 ~ hf_mzs:invisible_slab ["minecraft:facing_direction"="east"] replace`);
      boulder.runCommand(`setblock ~ ~2 ~2 hf_mzs:invisible_slab ["minecraft:facing_direction"="north"] replace`);
      boulder.runCommand(`setblock ~ ~2 ~-2 hf_mzs:invisible_slab ["minecraft:facing_direction"="south"] replace`);
    }
  } else {
    if (variant >= 0) {
      boulder.runCommand(`setblock ~ ~ ~ air [] replace`);
    }
    if (variant >= 1) {
      boulder.runCommand(`setblock ~ ~ ~ air [] replace`);
      boulder.runCommand(`setblock ~ ~-1 ~ air [] replace`);
      boulder.runCommand(`setblock ~1 ~ ~ air [] replace`);
      boulder.runCommand(`setblock ~-1 ~ ~ air [] replace`);
      boulder.runCommand(`setblock ~ ~ ~1 air [] replace`);
      boulder.runCommand(`setblock ~ ~ ~-1 air [] replace`);
    }
    if (variant >= 2) {
      boulder.runCommand(`setblock ~ ~1 ~ air [] replace`);
      boulder.runCommand(`setblock ~1 ~1 ~ air [] replace`);
      boulder.runCommand(`setblock ~-1 ~1 ~ air [] replace`);
      boulder.runCommand(`setblock ~ ~1 ~1 air [] replace`);
      boulder.runCommand(`setblock ~ ~1 ~-1 air [] replace`);
      boulder.runCommand(`setblock ~-1 ~1 ~-1 air [] replace`);
      boulder.runCommand(`setblock ~1 ~1 ~1 air [] replace`);
      boulder.runCommand(`setblock ~-1 ~1 ~1 air [] replace`);
      boulder.runCommand(`setblock ~1 ~1 ~-1 air [] replace`);
    }
    if (variant >= 3) {
      boulder.runCommand(`fill ~-1 ~2 ~-1 ~1 ~2 ~1 air [] replace`);
      boulder.runCommand(`setblock ~2 ~2 ~ air [] replace`);
      boulder.runCommand(`setblock ~-2 ~2 ~ air [] replace`);
      boulder.runCommand(`setblock ~ ~2 ~2 air [] replace`);
      boulder.runCommand(`setblock ~ ~2 ~-2 air [] replace`);
    }
  }
}

export function tick1() {
  const getBoulders = mc.world.getDimension("overworld").getEntities({ type: "hf_mzs:boulder" });
  const getBouldersN = mc.world.getDimension("nether").getEntities({ type: "hf_mzs:boulder" });
  const getBouldersE = mc.world.getDimension("the_end").getEntities({ type: "hf_mzs:boulder" });

  getBoulders.push(...getBouldersN, ...getBouldersE);

  for (let boulder of getBoulders) {
    if (boulder.getProperty("hf_mzs:is_orbiting") && !boulder.getProperty("hf_mzs:launched")) {
      let angleModifier = 0;
      let variant = boulder.getComponent("minecraft:mark_variant");

      switch (variant.value) {
        case 0:
          angleModifier = 0.05;
          break;
        case 1:
          angleModifier = 0.025;
          break;
        case 2:
          angleModifier = 0.015;
          break;
        case 3:
          angleModifier = 0.0075;
          break;
      }
      const angle = boulder.getDynamicProperty("hf_mzs:orbit_angle");

      let c = boulder.getDynamicProperty("hf_mzs:orbit_center");
      c = c.split(",");
      const orbitCenter = { x: parseFloat(c[0]), y: parseFloat(c[1]), z: parseFloat(c[2]) };

      let s = boulder.getDynamicProperty("hf_mzs:orbit_start");
      s = s.split(",");
      const orbitStart = { x: parseFloat(s[0]), y: parseFloat(s[1]), z: parseFloat(s[2]) };

      const radius = parseFloat(boulder.getDynamicProperty("hf_mzs:orbit_radius"));

      let nextLoc = orbitStart;
      nextLoc.x = orbitCenter.x + Math.cos(angle) * radius;
      nextLoc.z = orbitCenter.z + Math.sin(angle) * radius;

      boulder.teleport(nextLoc);
      boulder.setDynamicProperty("hf_mzs:orbit_angle", angle + angleModifier);
    }

    // Crumbling platforms
    if (boulder.getProperty("hf_mzs:is_crumbling")) continue;
    const skinId = boulder.getComponent("minecraft:skin_id");
    if (skinId && skinId.value === 1) {
      const players = boulder.dimension.getEntities({
        location: boulder.location,
        maxDistance: 5,
        type: "minecraft:player",
      });
      for (const player of players) {
        if (entityIsOnBoulder(player, boulder)) {
          const variant = boulder.getComponent("minecraft:mark_variant");
          const dimension = boulder.dimension;
          const location = boulder.location;
          const v = variant.value;
          const id = boulder.getTags()[0];
          const sculptor = mc.world.getEntity(id);
          const center = boulder.dimension.getBlock(boulder.location).center();
          center.y += 0.5;
          boulder.runCommand("/playsound hf_mzs:pillar_rising @a[r=50] ~ ~ ~ 0.3 1.2 0.3");

          if (vector.distance(player.location, center) < variant.value == 0 ? 0.25 : 1) {
            boulder.setProperty("hf_mzs:is_crumbling", true);
            mc.system.runTimeout(() => {
              if (!boulder.isValid()) return;
              boulder.runCommand("/stopsound @a[r=50] hf_mzs:pillar_rising");
              boulder.triggerEvent("hf_mzs:on_hit");
              mc.system.runTimeout(() => {
                if (sculptor.getProperty("hf_mzs:is_testing")) {
                  const b = dimension.spawnEntity(
                    `hf_mzs:boulder<hf_mzs:sculptor_test_crumbling_${v == 0 ? "small" : "medium"}>`,
                    location
                  );
                  b.addTag(id);
                  fillBlocks(b, v);
                }
              }, 70);
            }, 70);
          }
        }
      }
    }
  }
}

export function entityIsOnBoulder(entity, boulder) {
  const variant = boulder.getComponent("minecraft:mark_variant");

  let radius = 1;
  let yOffset = 1;

  switch (variant.value) {
    case 0:
      radius = 1;
      yOffset = 1;
      break;
    case 1:
      radius = 1.5;
      yOffset = 1;
      break;
    case 2:
      radius = 2;
      yOffset = 2;
      break;
    case 3:
      radius = 2.5;
      yOffset = 3;
      break;
  }

  const loc = boulder.location;
  loc.y = Math.floor(loc.y) + yOffset;

  return entity.location.y >= loc.y && vector.distance(entity.location, loc) <= radius;
}

export const excludedBlocks = [
  "minecraft:barrier",
  "hf_mzs:invisible_block",
  "hf_mzs:invisible_slab",
  "hf_mzs:invisible_quarter",
];
