import * as mc from "@minecraft/server";
import * as ui from "@minecraft/server-ui";
import * as vector from "../utils/vector";
import * as selectors from "../utils/selectors";
import * as utils from "../utils/generalUtils";

const SUNSTRIKE_LENGTH = 35;
const SUNSTRIKE_HIT_KF = 10; // kf = keyframe (when the damage happens)
const SUNSTRIKE_CD_MAX = 50; // cd = cooldown

export const SOLAR_FLARE_LENGTH = 34;
export const SOLAR_FLARE_HIT_KF = 14;
export const SOLAR_FLARE_DIST = 5;
export const SOLAR_FLARE_DAMAGE = 2;
export const SOLAR_FLARE_KB = 15;

export const SOLAR_BEAM_LENGTH = 120;
export const SOLAR_BEAM_HIT_KF = 30;
export const SOLAR_BEAM_DAMAGE_LENGTH = 60; // the length of the damaging part
export const SOLAR_BEAM_CD = 230;
export const SOLAR_BEAM_DISTANCE = 64;
export const SOLAR_BEAM_DAMAGE = 3;
export const SOLAR_BEAM_FIRE_TIME = 1.5;

const SUPERNOVA_LENGTH = 120;
export const SUPERNOVA_HIT_KF = 10;
const SUPERNOVA_DAMAGE_LENGTH = 90; // the length of the damaging part
export const SUPERNOVA_PAUSE_KF = 20;
export const SUPERNOVA_PUSH_KF = 40;
export const SUPERNOVA_CD = 230;
export const SUPERNOVA_DAMAGE = 9;
export const SUPERNOVA_PULL_DIST = 12;
export const SUPERNOVA_PUSH_DIST = 14;
export const SUPERNOVA_PUSH_KB = 0.8;

const SPAWN_LENGTH = 24;
const SPAWN_HIT_KF = 5;
const SPAWN_CD = 200;
const SPAWN_COUNT = 3;
const SPAWN_INTERRUPT_DIST = 6;

export function eventBehavior(event) {
  const entity = event.entity;
  //mc.world.sendMessage(entity.typeId+':    '+event.eventId+'')

  if (event.eventId === "minecraft:entity_spawned") {
    entity.setDynamicProperty("hf_mzs:threshhold", 0);
    entity.setRotation({
      x: 0,
      y: Math.round(entity.getRotation().y / 90) * 90,
    });
    entity.setProperty("hf_mzs:initial_rotation", entity.getRotation().y);
    return;
  }
  if (event.eventId === "register") {
    entity.setProperty("hf_mzs:attack_mode", "none");
    entity.setDynamicProperty("hf_mzs:threshhold", 0);
    entity.setDynamicProperty("hf_mzs:ding_cooldown", 0);
    entity.setDynamicProperty("hf_mzs:ticking", true);
    if (entity.getDynamicProperty("hf_mzs:has_spawned") === false) {
      entity.setDynamicProperty("hf_mzs:has_spawned", true);
      entity.setRotation({
        x: 0,
        y: Math.floor(entity.getRotation().y / 90) * 90,
      });
      entity.setProperty("hf_mzs:initial_rotation", entity.getRotation().y);
      // mc.world.sendMessage(`${entity.getProperty("hf_mzs:initial_rotation")}`);
    }
    return;
  }

  if (event.eventId === "attempt_menu_open") {
    const player = getNearestPlayer(entity);
    if (player.getGameMode() === "creative") return;
    // first time purchase
    //mc.world.sendMessage(`${player.getDynamicProperty(`hf_mzs:bought_${entity.id}`)}`);
    if (player.getDynamicProperty(`hf_mzs:bought_${entity.id}`) === undefined) {
      const form = new ui.ActionFormData().title({ translate: "menu.hf_mzs.umvuthi_trade_name" });

      const inventory = player.getComponent("inventory");
      if (!inventory || !inventory.container) return;
      const { container } = inventory;

      let goldCounter = 0;
      let hasSunsBlessing = false;
      for (let i = 0; i <= inventory.inventorySize - 1; i++) {
        const itemSearch = container.getItem(i);
        if (itemSearch === undefined) continue;
        if (itemSearch.typeId === "minecraft:gold_block") goldCounter += itemSearch.amount;
        if (itemSearch.typeId === "hf_mzs:suns_blessing") hasSunsBlessing = true;
        if (goldCounter >= 7) break;
      }

      if (goldCounter >= 7) {
        form.body({ translate: "menu.hf_mzs.umvuthi_trade_content_buy" });
        form.button({ translate: "menu.hf_mzs.umvuthi_trade_button_buy" });
      } else {
        form.body({ translate: "menu.hf_mzs.umvuthi_trade_content_cant" });
        form.button({ translate: "menu.hf_mzs.umvuthi_trade_button_cant" });
      }

      form.show(player).then((response) => {
        if (response.selection !== 0 || goldCounter < 7) return;

        for (let i = 0; i < 7; i++) {
          player.runCommand("/clear @s minecraft:gold_block 0 1");
        }
        if (hasSunsBlessing) {
          for (let i = 0; i <= inventory.inventorySize - 1; i++) {
            const itemSearch = container.getItem(i);
            if (itemSearch === undefined || itemSearch.typeId !== "hf_mzs:suns_blessing") continue;
            const newItem = itemSearch.clone();
            newItem.getComponent("minecraft:durability").damage = 0;
            newItem.setDynamicProperty("hf_mzs:was_used", false);
            container.setItem(i, newItem);
            player.setDynamicProperty(`hf_mzs:bought_${entity.id}`, true);
            entity.triggerEvent("bless");
            return;
          }
        } else {
          const item = new mc.ItemStack("hf_mzs:suns_blessing");
          item.setDynamicProperty("hf_mzs:was_used", false);
          player.dimension.spawnItem(item, player.location);
          player.setDynamicProperty(`hf_mzs:bought_${entity.id}`, true);
          entity.triggerEvent("bless");
        }
      });
      return;
    }
    // refill
    else {
      const form = new ui.ActionFormData()
        .title({ translate: "menu.hf_mzs.umvuthi_trade_name" })
        .body({ translate: "menu.hf_mzs.umvuthi_trade_content_refill" })
        .button({ translate: "menu.hf_mzs.umvuthi_trade_button_refill" });

      form.show(player).then((response) => {
        if (response.selection !== 0) return;
        const inventory = player.getComponent("inventory");
        if (!inventory || !inventory.container) return;
        const { container } = inventory;

        for (let i = 0; i <= inventory.inventorySize - 1; i++) {
          const itemSearch = container.getItem(i);
          if (itemSearch === undefined || itemSearch.typeId !== "hf_mzs:suns_blessing") continue;
          const newItem = itemSearch.clone();
          newItem.getComponent("minecraft:durability").damage = 0;
          newItem.setDynamicProperty("hf_mzs:was_used", false);
          container.setItem(i, newItem);
          entity.triggerEvent("bless");
          return;
        }
        const item = new mc.ItemStack("hf_mzs:suns_blessing");
        item.setDynamicProperty("hf_mzs:was_used", false);
        player.dimension.spawnItem(item, player.location);
        entity.triggerEvent("bless");
      });
      return;
    }
  }
  if (event.eventId === "bless") {
    //mc.world.sendMessage("h");
    entity.setProperty("hf_mzs:is_blessing", true);
    mc.system.runTimeout(() => {
      entity.setProperty("hf_mzs:is_blessing", false);
    }, 4);
  }

  //mc.world.sendMessage(`${event.eventId}   ${entity.getProperty("hf_mzs:attack_mode")}`);
  if (event.eventId === "attack_sunstrike") {
    if (entity.getProperty("hf_mzs:attack_mode") !== "none") {
      return;
    }
    const health = entity.getComponent("health").currentValue;
    //const maxHealth = healthComponent.effectiveMax;
    // delay =  50 - 20*(clamp(1-(health/maxHealth), 0, 0.6)/0.6)
    const delay = Math.min(Math.max(health / 3, 30), SUNSTRIKE_CD_MAX);
    entity.setProperty("hf_mzs:attack_mode", "sunstrike");
    entity.setProperty("hf_mzs:delay_sunstrike", delay);
    mc.system.runTimeout(() => {
      if (entity.getProperty("hf_mzs:attack_mode") !== "sunstrike") {
        return;
      }
      //mc.world.sendMessage('strike')
      if (getNearestPlayer(entity) !== undefined && getNearestPlayer(entity).isValid()) {
        const playerPos = getNearestPlayer(entity).location;
        if (getNearestPlayer(entity).getGameMode() === mc.GameMode.survival || getNearestPlayer(entity).getGameMode() === mc.GameMode.adventure) {
          const offset = vector.multiply(vector.flatten(getNearestPlayer(entity).getVelocity(), "y", false), 30);
          //mc.world.sendMessage(`${vector.string(vector.multiply(vector.flatten(getNearestPlayer(entity).getVelocity(), 'y', false), 30))}  vvvvvv ${vector.string(vector.add(vector.add(playerPos, vector.up), offset))}`);
          const blockAtOffset = entity.dimension.getBlockFromRay(vector.add(vector.add(playerPos, { x: 0, y: 10, z: 0 }), offset), vector.down, {
            maxDistance: 20,
            includePassableBlocks: false,
            includeLiquidBlocks: false,
          });
          if (
            blockAtOffset !== undefined &&
            entity.dimension.getBlockFromRay(playerPos, vector.down, {
              maxDistance: 1,
              includePassableBlocks: false,
              includeLiquidBlocks: false,
            }) !== undefined &&
            entity.dimension.getBlockFromRay(playerPos, vector.up, {
              maxDistance: 10,
              includePassableBlocks: false,
              includeLiquidBlocks: false,
              excludeTypes: ["glass", "stained_glass"],
            }) === undefined
          ) {
            const strike = entity.dimension.spawnEntity("hf_mzs:sunstrike", vector.add(blockAtOffset.block.location, blockAtOffset.faceLocation));
            strike.setDynamicProperty("hf_mzs:caster_id", entity.id);
          }
        }
      }
      mc.system.runTimeout(() => {
        if (!entity.isValid()) return;
        entity.setProperty("hf_mzs:attack_mode", "none");
      }, SUNSTRIKE_LENGTH - SUNSTRIKE_HIT_KF);
    }, SUNSTRIKE_HIT_KF);
    return;
  }
  if (event.eventId === "attack_solar_flare") {
    if (entity.getProperty("hf_mzs:attack_mode") !== "none") {
      return;
    }
    entity.setProperty("hf_mzs:attack_mode", "solar_flare");
    mc.system.runTimeout(() => {
      if (entity.getProperty("hf_mzs:attack_mode") !== "solar_flare") {
        return;
      }
      //mc.world.sendMessage('solar_flare')
      selectors
        .union(
          {
            location: entity.location,
            maxDistance: SOLAR_FLARE_DIST,
            excludeFamilies: ["inanimate"],
          },
          ["mob", "player"],
          entity.dimension,
          entity.id,
          false
        )
        .forEach((target) => {
          if (target.isValid() && (target.typeId.includes("umvuthana") ? target.getProperty("hf_mzs:tamed") : true)) {
            const dir = vector.normalize(vector.subtract(target.location, entity.location));
            target.applyKnockback(dir.x, dir.z, target.isOnGround ? SOLAR_FLARE_KB : SOLAR_FLARE_KB / 2, target.isOnGround ? 0.25 : 0.1);
            target.applyDamage(SOLAR_FLARE_DAMAGE, {
              cause: "entityAttack",
              damagingEntity: entity,
            });
          }
        });

      entity.dimension
        .getEntities({
          location: {
            x: entity.location.x,
            y: entity.location.y,
            z: entity.location.z,
          },
          maxDistance: 7,
          families: ["hf_mzs_boulder"],
        })
        .forEach((element) => {
          if (element.isValid()) element.runCommand("scriptevent hf_mzs:boulder_destroy");
        });
      mc.system.runTimeout(() => {
        entity.setProperty("hf_mzs:attack_mode", "none");
      }, SOLAR_FLARE_LENGTH - SOLAR_FLARE_HIT_KF);
    }, SOLAR_FLARE_HIT_KF);
    return;
  }
  if (event.eventId === "attack_solar_beam") {
    if (entity.getProperty("hf_mzs:attack_mode") !== "none") {
      return;
    }
    entity.setProperty("hf_mzs:attack_mode", "solar_beam");
    entity.setProperty("hf_mzs:solar_beam_rotation", entity.getProperty("hf_mzs:initial_rotation"));
    // laser beam visual effect
    mc.system.runTimeout(() => {
      if (entity.getProperty("hf_mzs:attack_mode") === "solar_beam" && entity.getDynamicProperty("hf_mzs:beam_id") === undefined || !mc.world.getEntity(entity.getDynamicProperty("hf_mzs:beam_id")))
        spawnBeam(entity);
    }, 26);

    mc.system.runTimeout(() => {
      if (entity.getProperty("hf_mzs:attack_mode") !== "solar_beam")
        return;

      entity.setDynamicProperty("hf_mzs:solar_beam", SOLAR_BEAM_DAMAGE_LENGTH);
      mc.system.runTimeout(() => {
        if (entity && entity.isValid()) {
          entity.setProperty("hf_mzs:attack_mode", "none");
          entity.setProperty("hf_mzs:delay_solar_beam", SOLAR_BEAM_CD);
        }
      }, SOLAR_BEAM_LENGTH - SOLAR_BEAM_HIT_KF);
    }, SOLAR_BEAM_HIT_KF);
    return;
  }
  if (event.eventId === "attack_supernova") {
    if (entity.getProperty("hf_mzs:attack_mode") !== "none") {
      return;
    }
    entity.setProperty("hf_mzs:attack_mode", "supernova");
    mc.system.runTimeout(() => {
      if (entity.getProperty("hf_mzs:attack_mode") !== "supernova") return;
      entity.runCommand("/fog @a push hf_mzs:supernova supernova");
      entity.setDynamicProperty("hf_mzs:supernova", SUPERNOVA_DAMAGE_LENGTH);
      mc.system.runTimeout(() => {
        entity.setProperty("hf_mzs:attack_mode", "none");
        entity.setProperty("hf_mzs:delay_supernova", SUPERNOVA_CD);
      }, SUPERNOVA_LENGTH - SUPERNOVA_HIT_KF);
    }, SUPERNOVA_HIT_KF);
    return;
  }
  if (event.eventId === "attack_spawn") {
    if (entity.getProperty("hf_mzs:attack_mode") !== "none") {
      return;
    }
    entity.setProperty("hf_mzs:attack_mode", "spawn");
    spawnFollower(0, entity);
    return;
  }
  if (event.eventId === "spawn_crane") {
    if (entity.getProperty("hf_mzs:attack_mode") !== "none") {
      return;
    }
    entity.setProperty("hf_mzs:attack_mode", "spawn");
    spawnCrane(0, entity);
    return;
  }
  if (event.eventId === "death") {
    selectors
      .union(
        {
          location: entity.location,
          maxDistance: 32,
          excludeFamilies: ["inanimate"],
        },
        ["hf_mzs_umvuthana"],
        entity.dimension,
        entity.id,
        false
      )
      .forEach((target) => {
        if (target.isValid() && !target.getProperty("hf_mzs:tamed")) {
          if (!target.getProperty("hf_mzs:spawn") && !target.getProperty("hf_mzs:teleport")) {
            target.runCommand("/damage @s 400");
          } else {
            target.remove();
          }
        }
      });
    mc.system.runTimeout(() => {
      if (!event.entity.isValid())
        return;
      event.entity.triggerEvent("drop");
    }, 145);
    return;
  }
}
export function hurtBehavior(event) {
  event.hurtEntity.setProperty("hf_mzs:time_since_hit", 0);
  let threshold = event.hurtEntity.getDynamicProperty("hf_mzs:threshhold");
  threshold += event.damage;
  event.hurtEntity.setDynamicProperty("hf_mzs:threshhold", Math.min(threshold, 45));
}

export function spawnBeam(entity) {
  //mc.world.sendMessage(`hi`);
  if (entity.getProperty("hf_mzs:attack_mode") !== "solar_beam")
    return;
  let loc = entity.location;
  loc.y += 1;
  loc = vector.add(loc, vector.multiply(vector.flatten(entity.getViewDirection(), "y"), 0));
  const beam = entity.dimension.spawnEntity("hf_mzs:sun_beam_player<hf_mzs:umvuthi>", loc);
  beam.setProperty("hf_mzs:x_rot", 0);
  beam.setProperty("hf_mzs:y_rot", entity.getProperty("hf_mzs:initial_rotation"));
  //mc.world.sendMessage(`${beam.getProperty("hf_mzs:y_rot")}`);

  entity.setDynamicProperty("hf_mzs:beam_id", beam.id);
}

export function tick5(entity) {
  if (entity.getDynamicProperty("hf_mzs:sunblocked_timer") > 0) {
    entity.setDynamicProperty("hf_mzs:sunblocked_timer", entity.getDynamicProperty("hf_mzs:sunblocked_timer") - 1);
    if (entity.getDynamicProperty("hf_mzs:sunblocked_timer") === 0) entity.setProperty("hf_mzs:sunblocked", false);
  }
  cooldowns(entity);
  if (!entity.getProperty("hf_mzs:can_spawn")) checkSpawn(entity);
  if (entity.getDynamicProperty("hf_mzs:solar_beam") > 0) {
    solarBeam(entity);
  }
  // leg rotation logic
  const rot = entity.getProperty("hf_mzs:initial_rotation");
  let pos = entity.location;
  pos.y = pos.y - 0.6;
  const dir = {
    x: -Math.sin((rot / 180) * Math.PI),
    y: 0,
    z: Math.cos((rot / 180) * Math.PI),
  };
  pos = vector.add(pos, dir);

  const centre = entity.dimension.getBlock(pos);
  const left = entity.dimension.getBlock(vector.add(pos, vector.cross(dir, vector.up)));
  const right = entity.dimension.getBlock(vector.add(pos, vector.cross(dir, vector.down)));
  if (centre === undefined || left === undefined || right === undefined) return;
  if (!entity.getProperty("hf_mzs:feet_up") && (!left.isAir || !right.isAir || !centre.isAir)) entity.setProperty("hf_mzs:feet_up", true);
  else if (entity.getProperty("hf_mzs:feet_up") && left.isAir && right.isAir && centre.isAir) entity.setProperty("hf_mzs:feet_up", false);

  // healing logic
  if (!entity.getProperty("hf_mzs:has_target")) {
    const time = entity.getProperty("hf_mzs:time_since_hit");
    if (time < 75) {
      entity.setProperty("hf_mzs:time_since_hit", time + 5);
    } else {
      entity.runCommand("/effect @s instant_health 1 0 true");
    }
  }

  // check if player is behind
  const player = getNearestPlayer(entity);
  if (player) {
    const playerDir = vector.subtract(player.location, entity.location);
    const hRot = -(Math.atan2(playerDir.x, playerDir.z) * 180) / Math.PI;
    entity.setProperty("hf_mzs:player_behind", Math.abs(hRot-entity.getProperty("hf_mzs:initial_rotation")) > 90);
  }
  //mc.world.sendMessage(`${entity.getProperty("hf_mzs:player_behind")}`);
}
// destroy geomancy projectiles
export function tick1(entity) {
  entity.setRotation({
    x: 0,
    y: entity.getProperty("hf_mzs:initial_rotation"),
  });
  //mc.world.sendMessage(`${entity.getDynamicProperty("hf_mzs:threshhold")}    ${entity.getProperty("hf_mzs:has_target")}    ${entity.getProperty("hf_mzs:attack_mode")}`)
  if (entity.getDynamicProperty("hf_mzs:ticking") === undefined) return;
  if (entity.getDynamicProperty("hf_mzs:supernova") > 0) supernova(entity);
  if (entity.isValid() && entity.getDynamicProperty("hf_mzs:threshhold") >= 45 && entity.getProperty("hf_mzs:attack_mode") === "none" && !entity.getProperty("hf_mzs:death")) {
    entity.triggerEvent("spawn_crane");
    entity.setDynamicProperty("hf_mzs:threshhold", 0);
  }

  if (entity.getProperty("hf_mzs:attack_mode") !== "none") return;
  const boulder = entity.dimension.getEntities({
    location: {
      x: entity.location.x,
      y: entity.location.y,
      z: entity.location.z,
    },
    maxDistance: 16,
    families: ["hf_mzs_boulder"],
  })[0];
  if (boulder === undefined || !boulder.isValid()) return;
  let c = boulder.getDynamicProperty("hf_mzs:flying_force");
  if (c === undefined) {
    if (vector.magnitude(vector.subtract(boulder.location, entity.location)) < 7) entity.triggerEvent("attack_solar_flare");
    return;
  }
  c = c.split(",");
  const dir = { x: parseFloat(c[0]), y: parseFloat(c[1]), z: parseFloat(c[2]) };

  let nextLoc = vector.add(boulder.location, dir);

  if (vector.magnitude(vector.subtract(nextLoc, entity.location)) < 9.5) entity.triggerEvent("attack_solar_flare");
}

export function tick1alt(entity) {
  // push
  if (!entity.getProperty("hf_mzs:death")) {
    const ens = selectors.union(
      {
        location: entity.location,
        maxDistance: 1.7,
        excludeFamilies: ["inanimate"],
      },
      ["player", "mob"],
      entity.dimension,
      entity.id
    );
    for (const e of ens) {
      const f = vector.subtract(e.location, entity.location);
      e.applyKnockback(f.x, f.z, 0.25, 0);
    }
  }

  // beam visuals
  const b = entity.getDynamicProperty("hf_mzs:beam_id");
  //mc.world.sendMessage(`${b}`);
  if (b) {
    const beam = mc.world.getEntity(b);
    const player = getNearestPlayer(entity);

    if (beam && beam.isValid() && player && player.isValid()) {
      const pLoc = player.getHeadLocation();
      pLoc.y -= 1.2;
      const dir = vector.subtract(pLoc, beam.location);
      const vRot = 90 - (Math.acos(dir.y / vector.magnitude(dir)) * 180) / Math.PI;
      const hRot = -(Math.atan2(dir.x, dir.z) * 180) / Math.PI;
      const currHRot = beam.getProperty("hf_mzs:y_rot");
      if (Math.abs(entity.getProperty("hf_mzs:initial_rotation") - hRot) > 140)
        return;

      //mc.world.sendMessage(`${hRot}`);
      beam.setProperty("hf_mzs:y_rot", utils.lerp(currHRot, hRot, 0.15));
      entity.setProperty("hf_mzs:solar_beam_rotation", utils.lerp(currHRot, hRot, 0.15));
      //mc.world.sendMessage(`${beam.getProperty("hf_mzs:y_rot")}`);
      beam.setProperty("hf_mzs:x_rot", vRot);
    }
  }
  else {
    entity.setProperty("hf_mzs:solar_beam_rotation", entity.getProperty("hf_mzs:initial_rotation"));
  }
}

function cooldowns(entity) {
  const attack = entity.getProperty("hf_mzs:attack_mode");

  const sunstrike = entity.getProperty("hf_mzs:delay_sunstrike");
  const solar_beam = entity.getProperty("hf_mzs:delay_solar_beam");
  const supernova = entity.getProperty("hf_mzs:delay_supernova");
  const spawn = entity.getProperty("hf_mzs:delay_spawn");

  if (sunstrike > 0) entity.setProperty("hf_mzs:delay_sunstrike", Math.max(0, sunstrike - 5));
  if (solar_beam > 0 && attack !== "supernova") entity.setProperty("hf_mzs:delay_solar_beam", solar_beam - 5);
  if (supernova > 0 && attack !== "solar_beam") entity.setProperty("hf_mzs:delay_supernova", supernova - 5);
  if (spawn > 0) entity.setProperty("hf_mzs:delay_spawn", spawn - 5);
}
function supernova(entity) {
  const supernovaTime = entity.getDynamicProperty("hf_mzs:supernova");
  // Pulls everything in within its range
  if (supernovaTime >= SUPERNOVA_DAMAGE_LENGTH - SUPERNOVA_PAUSE_KF) {
    const entities = selectors.union(
      {
        location: entity.location,
        maxDistance: SUPERNOVA_PULL_DIST,
        excludeFamilies: ["inanimate"],
      },
      ["mob", "player"],
      entity.dimension,
      entity.id
    );
    for (let i = 0; i < entities.length; i++) {
      if (!entities[i].isValid() || entities[i].hasTag(entity.id)) continue;
      if (entities[i].typeId.includes("umvuthana") ? !entities[i].getProperty("hf_mzs:tamed") : false) continue;
      const supernovaCentre = vector.add(vector.add(entity.location, vector.multiply(vector.up, 3)), vector.flatten(entity.getViewDirection(), "y"));
      const dir = vector.subtract(supernovaCentre, entities[i].location);
      entities[i].applyKnockback(dir.x, dir.z, 0.4, dir.y > 0 ? 0.3 : -0.3);
      //entities[i].setOnFire(0.4);
    }
    //mc.world.sendMessage('pull');
  }
  // After a short cooldown, it starts blasting away
  else if (supernovaTime < SUPERNOVA_DAMAGE_LENGTH - SUPERNOVA_PUSH_KF) {
    entity.runCommand("/fog @a remove supernova");
    entity.runCommand("/camerashake add @a[r=16] 0.1 0.1 positional");
    const entities = selectors.union(
      {
        location: entity.location,
        maxDistance: SUPERNOVA_PUSH_DIST,
        excludeFamilies: ["inanimate"],
      },
      ["mob", "player"],
      entity.dimension,
      entity.id
    );
    for (let i = 0; i < entities.length; i++) {
      if (!entities[i].isValid()) continue;
      if (entities[i].typeId.includes("umvuthana") ? !entities[i].getProperty("hf_mzs:tamed") : false) continue;
      const dir = vector.subtract(entities[i].location, entity.location);
      entities[i].applyKnockback(dir.x, dir.z, SUPERNOVA_PUSH_KB, entities[i].isOnGround ? 0.6 : 0.1);
      entities[i].applyDamage(SUPERNOVA_DAMAGE, {
        cause: "fire",
        damagingEntity: entity,
      });
      entities[i].setOnFire(1.4);
    }
    //mc.world.sendMessage('boom');
  }
  entity.setDynamicProperty("hf_mzs:supernova", supernovaTime - 1);
}
function solarBeam(entity) {
  // entity.runCommand("/tp @s ~~~ facing @p");
  entity.setDynamicProperty("hf_mzs:solar_beam", entity.getDynamicProperty("hf_mzs:solar_beam") - 5);
  //mc.world.sendMessage('beam');

  const beam = mc.world.getEntity(entity.getDynamicProperty("hf_mzs:beam_id"));
  if (!beam) return;
  const yawRad = (beam.getProperty("hf_mzs:y_rot") + 90) * (Math.PI / 180);
  const pitchRad = beam.getProperty("hf_mzs:x_rot") * (Math.PI / 180);

  const dir = {
    x: Math.cos(yawRad) * Math.cos(pitchRad),
    y: Math.sin(pitchRad),
    z: Math.sin(yawRad) * Math.cos(pitchRad),
  };

  const targets = entity.dimension.getEntitiesFromRay(beam.location, dir, {
    maxDistance: SOLAR_BEAM_DISTANCE,
    excludeFamilies: ["inanimate"],
    excludeTags: [entity.id],
  });
  /*
  const targets = entity.getEntitiesFromViewDirection({
    maxDistance: SOLAR_BEAM_DISTANCE,
    excludeFamilies: ["hf_mzs_umvuthana", "inanimate"],
  });
  */
  for (let target of targets) {
    if (target === undefined || !target.entity.isValid() || target.entity.typeId === "hf_mzs:sun_beam_player" || target.entity.typeId === "hf_mzs:umvuthi")
      continue;
    if (target.entity.typeId.includes("umvuthana") ? !target.entity.getProperty("hf_mzs:tamed") : false) continue;
    const dir = vector.subtract(target.entity.location, entity.location);
    target.entity.applyKnockback(dir.x, dir.z, target.entity.isOnGround ? 1 : 0.25, -0.25);
    target.entity.applyDamage(SOLAR_BEAM_DAMAGE, {
      cause: "fire",
      damagingEntity: entity,
    });
    target.entity.setOnFire(SOLAR_BEAM_FIRE_TIME);
  }
}

// Umvuthi has a 1/80 chance to spawn followers every tick (1/16 per
// 5 ticks) if there are less than 4 umvuthana within 50 blocks of him
function checkSpawn(entity) {
  const random = Math.floor(Math.random() * 17);
  const umvuthanaCount = entity.dimension.getEntities({
    families: ["hf_mzs_umvuthana"],
    excludeFamilies: ["hf_mzs_umvuthi"],
    maxDistance: 50,
    location: entity.location,
  }).length;
  //mc.world.sendMessage(umvuthanaCount + "   " + random);
  entity.setProperty("hf_mzs:can_spawn", umvuthanaCount < 4 && random === 0);
}
// Spawn N umvuthana, then end attack and apply cd
function spawnFollower(iteration, entity) {
  if (getNearestPlayer(entity) === undefined) return;
  const dist = vector.magnitude(vector.subtract(getNearestPlayer(entity).location, entity.location));
  if (iteration === SPAWN_COUNT || dist <= SPAWN_INTERRUPT_DIST) {
    entity.setProperty("hf_mzs:attack_mode", "none");
    entity.setProperty("hf_mzs:delay_spawn", SPAWN_CD);
    entity.setProperty("hf_mzs:can_spawn", false);
    return;
  }
  mc.system.runTimeout(() => {
    if (entity.getProperty("hf_mzs:attack_mode") !== "spawn") {
      entity.setProperty("hf_mzs:delay_spawn", SPAWN_CD);
      entity.setProperty("hf_mzs:can_spawn", false);
      return;
    }
    //mc.world.sendMessage("spawn"+iteration);
    const mask = entity.dimension.spawnEntity("hf_mzs:umvuthana", entity.getHeadLocation());
    mask.triggerEvent("spawn");
    mask.setProperty("hf_mzs:from_village", true);
    mask.setProperty("hf_mzs:y_rot", entity.getRotation().y);
    mask.applyImpulse(vector.add(vector.multiply(vector.flatten(entity.getViewDirection(), "y"), 2), vector.random(0.2)));

    mc.system.runTimeout(() => {
      iteration++;
      spawnFollower(iteration, entity);
    }, SPAWN_LENGTH - SPAWN_HIT_KF);
  }, SPAWN_HIT_KF);
}
function spawnCrane(iteration, entity) {
  if (!entity.isValid()) return;
  if (iteration === SPAWN_COUNT) {
    entity.setProperty("hf_mzs:attack_mode", "none");
    entity.setProperty("hf_mzs:delay_spawn", SPAWN_CD);
    entity.setProperty("hf_mzs:can_spawn", false);
    return;
  }
  mc.system.runTimeout(() => {
    if (!entity.isValid()) {
      return;
    }
    const rot = entity.getProperty("hf_mzs:initial_rotation") + (Math.random() - 0.5) * 100 + 90;
    const rotR = (rot / 180) * Math.PI;
    //mc.world.sendMessage(`${rot}   ${rotR}   ${Math.cos(rotR)}   ${Math.sin(rotR)}`);
    const pos = {
      x: entity.location.x + Math.cos(rotR) * (12 + Math.random() * 4),
      z: entity.location.z + Math.sin(rotR) * (12 + Math.random() * 4),
    };

    const mask = entity.dimension.spawnEntity("hf_mzs:umvuthana_crane", entity.getHeadLocation());
    mask.setDynamicProperty("hf_mzs:x_pos", pos.x);
    mask.setDynamicProperty("hf_mzs:z_pos", pos.z);

    mask.addTag(entity.id);
    mask.triggerEvent("spawn");

    mask.setProperty("hf_mzs:y_rot", entity.getRotation().y);
    mask.applyImpulse(vector.add(vector.multiply(vector.flatten(entity.getViewDirection(), "y"), 2), vector.random(0.3)));

    mc.system.runTimeout(() => {
      spawnCrane(iteration + 1, entity);
    }, SPAWN_LENGTH - SPAWN_HIT_KF);
  }, SPAWN_HIT_KF);
}

export function getNearestPlayer(entity) {
  const player = entity.dimension.getEntities({
    families: ["player"],
    maxDistance: 64,
    location: entity.location,
  })[0];
  if (player === undefined) return undefined;
  return player;
}
