import * as mc from "@minecraft/server";
import * as vector from "../utils/vector";
import * as selectors from "../utils/selectors";
import * as umvuthana from "./umvuthana";

const validGround = {
  "minecraft:grass_block": true,
  "minecraft:dirt": true,
  "minecraft:acacia_slab": true,
};

export function eventBehavior(event) {
  umvuthana.eventBehavior(event);

  if (event.eventId === "attempt_teleport") {
    if (event.entity.getDynamicProperty("hf_mzs:x_pos") === undefined) {
      event.entity.triggerEvent("minecraft:entity_spawned");
      return;
    }
    event.entity.setProperty("hf_mzs:teleport", true);
    event.entity.triggerEvent("teleport");
    return;
  }
  if (event.eventId === "teleport") {
    event.entity.setProperty("hf_mzs:teleport", true);
    mc.system.runTimeout(() => {
      let anchors = event.entity.dimension.getEntities({
        maxDistance: 32,
        families: ["hf_mzs_structure_umvuthana_village"],
        location: event.entity.location,
      });
      if (anchors[0] === undefined) {
        anchors = event.entity.dimension.getEntities({
          maxDistance: 32,
          families: ["hf_mzs_umvuthi"],
          location: event.entity.location,
        });
        if (anchors[0] === undefined) return;
      }
      const anchorPos = anchors[0].location;

      for (let i = 0; i < 50; i++) {
        const angle = Math.random() * 2 * Math.PI;
        const deltaPos = {
          x: anchorPos.x + Math.sin(angle) * (7 + Math.random() * 14),
          y: 300,
          z: anchorPos.z + Math.cos(angle) * (7 + Math.random() * 14),
        };
        const block = event.entity.dimension.getBlockFromRay(deltaPos, vector.down, {
          maxDistance: 900,
          includeLiquidBlocks: true,
          includePassableBlocks: false,
        });
        if (block === undefined || !validGround[block.block.typeId]) continue;
        const pos = block.block.location;

        // - They are 5 blocks or more away from another Crane;
        // - They are 5 blocks or more away from a player
        let entities = selectors.union(
          {
            location: pos,
            maxDistance: 5,
          },
          ["player", "hf_mzs_umvuthana_crane"],
          event.entity.dimension,
          event.entity.id
        );
        if (entities[0]) continue;
        // - They are 7 blocks or more away from Umvuthi
        entities = event.entity.dimension.getEntities({
          maxDistance: 7,
          families: ["hf_mzs_umvuthi"],
          location: event.entity.location,
        });
        if (entities[0]) continue;

        //success
        event.entity.teleport(vector.add(pos, vector.up));
        return;
      }
    }, 26);
    return;
  }
}

export function tick5(entity) {
  if (entity.getProperty("hf_mzs:spawn") || entity.getProperty("hf_mzs:teleport")) return;

  const owner = entity.getComponent("tameable").tamedToPlayer;
  if (validateTarget(entity, owner, 8)) {
    rotateToTarget(entity, owner);

    entity.runCommand(`/tp @s ~~~ facing ${owner.name}`);
    if (owner.getComponent("health").currentValue <= 10) {
      owner.getComponent("health").setCurrentValue(Math.min(owner.getComponent("health").currentValue + 0.2, 20));
    }
    entity.runCommand(`/effect ${owner.name} resistance 2 0 true`);
    owner.runCommand("/particle hf_mzs:umvuthana_crane_heal1 ~~~");
    owner.runCommand("/particle hf_mzs:umvuthana_crane_heal2 ~~~");
    return;
  } else {
    entity.setProperty("hf_mzs:healing", false);
  }

  const umvuthi = entity.dimension.getEntities({
    location: entity.location,
    maxDistance: 38,
    families: ["hf_mzs_umvuthi"],
  })[0];

  if (validateTarget(entity, umvuthi, 38)) {
    rotateToTarget(entity, umvuthi);

    entity.runCommand("/tp @s ~~~ facing @e[c=1, type=hf_mzs:umvuthi]");
    entity.runCommand("/effect @e[c=1, type=hf_mzs:umvuthi] resistance 1 100 true");
    umvuthi.setProperty("hf_mzs:sunblocked", true);
    umvuthi.setDynamicProperty("hf_mzs:sunblocked_timer", 3);
    if (umvuthi.getComponent("health").currentValue <= 150) {
      umvuthi.getComponent("health").setCurrentValue(Math.min(umvuthi.getComponent("health").currentValue + 0.1, 150));
    }
    return;
  }

  entity.setProperty("hf_mzs:healing", false);
  entity.setProperty("hf_mzs:distance", 0);
}

export function tick1(entity) {
  if (entity.getProperty("hf_mzs:tamed") || !entity.getProperty("hf_mzs:healing")) return;
  //mc.world.sendMessage(`${entity.getDynamicProperty('hf_mzs:dodge_cooldown')}`);
  if (entity.getDynamicProperty("hf_mzs:dodge_cooldown") > 0) {
    entity.setDynamicProperty("hf_mzs:dodge_cooldown", entity.getDynamicProperty("hf_mzs:dodge_cooldown") - 1);
    return;
  }
  const arrows = entity.dimension.getEntities({
    type: "arrow",
    maxDistance: 18,
    location: entity.location,
  });
  for (const arrow of arrows) {
    if (
      vector.magnitude(arrow.getVelocity()) > 0 &&
      (entity.getDynamicProperty("hf_mzs:dodge_cooldown") === 0 || !entity.getDynamicProperty("hf_mzs:dodge_cooldown"))
    ) {
      dodgeArrow(entity, arrow);
      return;
    }
  }
}

function dodgeArrow(entity, arrow) {
  const dir = vector.flatten(vector.subtract(entity.location, arrow.location), "y");
  let idk = vector.flatten(vector.normalize(arrow.getVelocity()), "y");
  //arrow.x *= -1;
  //mc.world.sendMessage(`Arrow Direction: x = ${arrow.x}, z = ${arrow.z}`);
  //mc.world.sendMessage(`Entity Direction: x = ${dir.x}, z = ${dir.z}`);
  const angle = idk.z * dir.x - idk.x * dir.z;
  //mc.world.sendMessage(`Cross Product Value: ${angle}`);
  //mc.world.sendMessage(`${angle>0 ? "right" : "left"} `)

  const impulseDir = vector.flatten(vector.cross(vector.normalize(arrow.getVelocity()), vector.up), "y");
  entity.applyImpulse(vector.multiply(impulseDir, angle >= 0 ? -1 : 1));
  entity.setDynamicProperty("hf_mzs:dodge_cooldown", 15);
}

function validateTarget(entity, target, maxDistance) {
  if (target === undefined || !target.isValid()) return false;
  if (
    target.typeId === "hf_mzs:umvuthi" &&
    (entity.getProperty("hf_mzs:tamed") ||
      target.getProperty("hf_mzs:death") ||
      !(target.getComponent("health").currentValue < 150 || target.getProperty("hf_mzs:has_target")))
  )
    return;
  if (target.typeId === "minecraft:player" && target.getComponent("health").currentValue >= 18.5) return;

  const delta = vector.subtract(target.location, entity.location);
  const distance = vector.magnitude(delta);

  if (distance > maxDistance) return false;

  const obstruction = entity.dimension.getBlockFromRay(
    vector.add(entity.location, { x: 0, y: 2.1, z: 0 }),
    vector.normalize(delta),
    {
      maxDistance: distance,
      includeLiquidBlocks: true,
      includePassableBlocks: false,
    }
  );
  if (obstruction !== undefined) return false;

  return true;
}

function rotateToTarget(entity, target) {
  const deltaPos = vector.subtract(target.location, entity.location);

  const xRot = -90 + (Math.acos(deltaPos.y / vector.magnitude(deltaPos)) / Math.PI) * 180;
  const yRot = (-Math.atan2(deltaPos.x, deltaPos.z) / Math.PI) * 180;
  //mc.world.sendMessage(`${Math.round(n.x*100)/100} ${Math.round(n.z*100)/100} :::
  //        ${Math.round(dir.x*100)/100} ${Math.round(dir.z*100)/100}`);
  entity.setProperty("hf_mzs:x_rot", xRot);
  entity.setProperty("hf_mzs:y_rot", yRot);

  entity.setProperty("hf_mzs:healing", true);
  if (target.typeId === "hf_mzs:umvuthi") entity.setProperty("hf_mzs:distance", vector.magnitude(deltaPos) * 0.028);
  else entity.setProperty("hf_mzs:distance", Math.max(0, vector.magnitude(deltaPos) * 0.028 - 0.02));

  entity.runCommand("/effect @s slowness 1 100 true");
}
