import { BlockPermutation, EntityComponentTypes, ItemComponentTypes, MolangVariableMap, system, TicksPerSecond, world } from "@minecraft/server";
import { blocks } from "./data";
import { isBlockMorph, Vector3Add, Vector3Scalar } from "./util";
import { failTeleport, failInsideBlock, failMorphAbility } from "./player_communication";
import { getMorph } from "./main";
import "./util";
function runPassiveAbilities(player, morph) {
  if (morph.can_fly) {
    flyPassive(player);
  }
  if (morph.id === "spider" || morph.id === "cave_spider") {
    climbPassive(player);
  }
}
function flyPassive(player) {
  if (player.isJumping && !player.isOnGround) {
    player.addEffect("levitation", 11, { amplifier: 1, showParticles: false });
  } else {
    player.removeEffect("levitation");
  }
}
function climbPassive(player) {
  if (player.isInWater)
    return;
  const block = player.dimension.getBlock(player.location);
  if (block === void 0)
    return;
  const east = block.east(1);
  const west = block.west(1);
  const north = block.north(1);
  const south = block.south(1);
  const solidBlock = east?.isSolid() || west?.isSolid() || north?.isSolid() || south?.isSolid();
  if (!solidBlock)
    return;
  if (player.getRotation().x > 0)
    player.addEffect("slow_falling", 2, { showParticles: false });
  if (player.isJumping)
    player.applyKnockback(0, 0, 0, 0.22);
}
function runOnAttackAbilities(player, morph, entity) {
  switch (morph.id) {
    case "bee":
      entity.addEffect("poison", 2 * TicksPerSecond);
      break;
    case "bogged":
      entity.addEffect("poison", 5 * TicksPerSecond);
      break;
    case "cave_spider":
      entity.addEffect("poison", 5 * TicksPerSecond);
      break;
    case "husk":
      entity.addEffect("hunger", 5 * TicksPerSecond);
      break;
    case "pufferfish":
      entity.addEffect("poison", 5 * TicksPerSecond);
      break;
    case "slime":
      entity.addEffect("oozing", 5 * TicksPerSecond);
      break;
    case "stray":
      entity.addEffect("slowness", 5 * TicksPerSecond);
      break;
    case "witch":
      const rand = Math.random();
      if (rand > 0.66)
        entity.addEffect("poison", 2 * TicksPerSecond);
      else if (rand > 0.33)
        entity.addEffect("slowness", 2 * TicksPerSecond);
      break;
    case "wither_skeleton":
      entity.addEffect("wither", 5 * TicksPerSecond);
      break;
  }
}
function runOnInteractAbilities(player, itemStack, morph) {
  if (isBlockMorph(morph)) {
    return centerBlockMorph(player);
  }
  const cooldownComponent = itemStack.getComponent(ItemComponentTypes.Cooldown);
  var abilityUsed = true;
  var overwrite = true;
  if (cooldownComponent === void 0 || !cooldownComponent.isValid)
    return;
  if (cooldownComponent.getCooldownTicksRemaining(player) > 0)
    return;
  switch (morph.id) {
    case "blaze":
      blazeFireballAbility(player);
      break;
    case "breeze":
      breezeWindchargeAbility(player);
      break;
    case "camel":
      camelDashAbility(player);
      break;
    case "creeper":
      creeperExplodeAbility(player);
      break;
    case "cow":
      cowMooAbility(player);
      break;
    case "drowned":
      drownedTridentAbility(player);
      break;
    case "ender_dragon":
      enderDragonFireballAbility(player);
      break;
    case "enderman":
      abilityUsed = endermanTeleportAbility(player);
      if (!abilityUsed)
        overwrite = false;
      break;
    case "evoker":
      evokerFangAbility(player);
      break;
    case "ghast":
      ghastFireballAbility(player);
      break;
    case "goat":
      goatChargeAbility(player);
      break;
    case "iron_golem":
      ironGolemThrowAbility(player);
      break;
    case "llama":
      llamaSpitAbility(player);
      break;
    case "pig":
      pigOinkAbility(player);
      break;
    case "ravager":
      ravagerShoveAbility(player);
      break;
    case "shulker":
      abilityUsed = endermanTeleportAbility(player);
      if (!abilityUsed)
        overwrite = false;
      break;
    case "snow_golem":
      snowGolemSnowballAbility(player);
      break;
    case "squid":
      squidInkAbility(player);
      break;
    case "turtle":
      turtleEggAbility(player);
      break;
    case "trader_llama":
      llamaSpitAbility(player);
      break;
    case "warden":
      wardenSonicboomAbility(player);
      break;
    case "wither":
      witherSkullAbility(player);
      break;
    default:
      abilityUsed = false;
      break;
  }
  if (abilityUsed) {
    cooldownComponent.startCooldown(player);
  } else if (overwrite) {
    failMorphAbility(player);
  }
}
function centerBlockMorph(player) {
  const loc = player.location;
  const block = player.dimension.getBlock(loc);
  if (block === void 0 || !block.isValid)
    return;
  if (!block.isAir && block.typeId != "squaredreams_bam:fake_block")
    return failInsideBlock(player);
  const blockLoc = block.bottomCenter();
  player.teleport(blockLoc);
  const morph = getMorph(player);
  const mIndex = blocks.findIndex((x) => x === morph);
  const blockStates = { "squaredreams_bam:texture_bit_2": Math.floor(mIndex / 256), "squaredreams_bam:texture_bit_1": Math.floor(mIndex % 256 / 16), "squaredreams_bam:texture_bit_0": mIndex % 16 };
  player.dimension.setBlockPermutation(block.location, BlockPermutation.resolve("squaredreams_bam:fake_block", blockStates));
  player.setDynamicProperty("squaredreams_bam:block_frozen", `${blockLoc.x}/${blockLoc.y}/${blockLoc.z}`);
}
function stopCenterBlockMorph(player, blockLoc) {
  player.dimension.setBlockPermutation(blockLoc, BlockPermutation.resolve("minecraft:air"));
  player.setDynamicProperty("squaredreams_bam:block_frozen", false);
}
function shootProjectileAbility(player, projectileId, offset = 0.5, projectileVelocity = 1) {
  player.dimension.spawnEntity(`squaredreams_bam:dummy_projectile<squaredreams_bam:projectile.${projectileId}>`, Vector3Add(Vector3Add(player.location, { x: 0, y: offset, z: 0 }), player.getViewDirection()));
  system.run(() => {
    world.afterEvents.entitySpawn.subscribe((event) => {
      const { entity } = event;
      if (entity.typeId === `minecraft:${projectileId}`) {
        const projectileComponent = entity.getComponent(EntityComponentTypes.Projectile);
        projectileComponent.shoot(Vector3Scalar(player.getViewDirection(), projectileVelocity));
        projectileComponent.owner = player;
      }
    });
  });
}
function blazeFireballAbility(player) {
  const blazeShootDelay = 10;
  system.runTimeout(() => {
    shootProjectileAbility(player, "small_fireball");
    player.playSound("mob.blaze.shoot", { volume: 1 });
  }, 0);
  system.runTimeout(() => {
    shootProjectileAbility(player, "small_fireball");
    player.playSound("mob.blaze.shoot", { volume: 1 });
  }, blazeShootDelay * 1);
  system.runTimeout(() => {
    shootProjectileAbility(player, "small_fireball");
    player.playSound("mob.blaze.shoot", { volume: 1 });
  }, blazeShootDelay * 2);
  return;
}
function breezeWindchargeAbility(player) {
  const spawnLocation = Vector3Add(Vector3Add(player.location, { x: 0, y: 1.5, z: 0 }), player.getViewDirection());
  const projectile = player.dimension.spawnEntity("minecraft:wind_charge_projectile", spawnLocation);
  player.playSound("mob.breeze.shoot", { volume: 1 });
  const viewDirection = player.getViewDirection();
  const velocity = Vector3Scalar(viewDirection, 1.5);
  if (projectile) {
    const projectileComponent = projectile.getComponent(EntityComponentTypes.Projectile);
    projectileComponent.shoot(velocity);
    projectileComponent.owner = player;
  }
  return;
}
function camelDashAbility(player) {
  const facing = player.getViewDirection();
  player.applyKnockback(facing.x, facing.z, 4, 0.3);
  player.playSound("mob.camel.dash", { volume: 1 });
}
function creeperExplodeAbility(player) {
  const CreeperExplosionDelay = 30;
  player.playSound("mob.creeper.say", { volume: 1 });
  player.playSound("random.fuse", { volume: 1 });
  system.runTimeout(() => {
    player.dimension.createExplosion(player.location, 2, { source: player });
  }, CreeperExplosionDelay);
  return;
}
function cowMooAbility(player) {
  player.playSound("mob.cow.say", { volume: 1 });
}
function drownedTridentAbility(player) {
  player.playSound("mob.drowned.shoot", { volume: 1 });
  shootProjectileAbility(player, "thrown_trident", 1, 1.5);
  return;
}
function enderDragonFireballAbility(player) {
  player.playSound("mob.enderdragon.growl", { volume: 0.5 });
  player.playSound("mob.blaze.shoot", { volume: 0.5 });
  shootProjectileAbility(player, "dragon_fireball");
}
function endermanTeleportAbility(player) {
  var distance = 10;
  const viewDir = player.getViewDirection();
  var teleport = false;
  var teleportLoc = Vector3Add(player.getHeadLocation(), Vector3Scalar(viewDir, distance));
  while (!teleport && distance > 1) {
    teleport = endermanAttemptTeleport(player, teleportLoc);
    var teleportLoc = Vector3Add(player.getHeadLocation(), Vector3Scalar(viewDir, distance));
    distance--;
  }
  if (distance <= 1)
    return failTeleport(player);
  const blockLoc = player.dimension.getBlock(Vector3Add(player.location, Vector3Scalar(viewDir, distance)));
  if (blockLoc == void 0 || !blockLoc.isAir)
    return failTeleport(player);
  const attemptTeleport = player.tryTeleport(blockLoc.location, { checkForBlocks: true });
  player.playSound("mob.endermen.portal", { volume: 1 });
  player.addEffect("resistance", 20, { amplifier: 5, showParticles: false });
  if (!attemptTeleport)
    return failTeleport(player);
  return true;
}
function endermanAttemptTeleport(player, loc) {
  try {
    const blockLoc = player.dimension.getBlock(loc);
    return blockLoc?.isAir ?? false;
  } catch (error) {
    return false;
  }
}
function ghastFireballAbility(player) {
  const GhastFireballDelay = 10;
  player.playSound("mob.ghast.charge", { volume: 1 });
  system.runTimeout(() => {
    shootProjectileAbility(player, "fireball");
    player.playSound("mob.ghast.fireball", { volume: 1 });
  }, GhastFireballDelay);
}
function goatChargeAbility(player) {
  player.playSound("mob.goat.prepare_ram", { volume: 1 });
  player.dimension.spawnEntity(`squaredreams_bam:dummy_knockback<squaredreams_bam:knockback.goat>`, Vector3Add(player.location, player.getViewDirection()));
}
function evokerFangAbility(player) {
  const lookDirection = player.getViewDirection();
  const lookMagnitude = Math.sqrt(lookDirection.x ** 2 + lookDirection.z ** 2);
  const fangCount = 5;
  const fangDistance = 1.2;
  const x = lookDirection.x / lookMagnitude;
  const z = lookDirection.z / lookMagnitude;
  for (let i = 0; i < fangCount; i++) {
    player.runCommand(`summon minecraft:evocation_fang ~${(x * fangDistance * i).toFixed(2)} ~ ~${(z * fangDistance * i).toFixed(2)}`);
  }
}
function ironGolemThrowAbility(player) {
  player.playSound("mob.irongolem.throw", { volume: 1 });
  player.dimension.spawnEntity(`squaredreams_bam:dummy_knockback<squaredreams_bam:knockback.iron_golem>`, Vector3Add(player.location, player.getViewDirection()));
}
function pigOinkAbility(player) {
  player.playSound("mob.pig.say", { volume: 1 });
}
function llamaSpitAbility(player) {
  player.playSound("mob.llama.spit", { volume: 1 });
  shootProjectileAbility(player, "llama_spit", 0.8);
}
function ravagerShoveAbility(player) {
  player.playSound("mob.ravager.roar", { volume: 1 });
  player.dimension.spawnEntity(`squaredreams_bam:dummy_knockback<squaredreams_bam:knockback.ravager>`, Vector3Add(player.location, player.getViewDirection()));
}
function snowGolemSnowballAbility(player) {
  player.playSound("mob.snowgolem.shoot", { volume: 1 });
  shootProjectileAbility(player, "snowball", 1.2);
}
function squidInkAbility(player) {
  player.playSound("mob.squid.ink_squirt", { volume: 1 });
  const molang = new MolangVariableMap();
  molang.setFloat("particlecount", 10);
  molang.setFloat("particlesize", 1);
  molang.setFloat("is_outside_water", Number(player.isInWater));
  molang.setColorRGB("color", { red: 0, green: 0, blue: 0 });
  molang.setVector3("direction_vector", { x: 0, y: 0, z: 0 });
  molang.setVector3("aabb_dimension", { x: 2, y: 2, z: 2 });
  player.dimension.spawnParticle("minecraft:ink_emitter", player.location, molang);
  const entities = player.dimension.getEntities({ location: player.location, maxDistance: 5, minDistance: 0.01 });
  for (const entity of entities) {
    entity.addEffect("blindness", 5 * TicksPerSecond);
  }
}
function turtleEggAbility(player) {
  player.playSound("block.turtle_egg.drop", { volume: 1 });
  const overworld = player.dimension;
  overworld.runCommand(`fill ${player.location.x} ${player.location.y} ${player.location.z} ${player.location.x} ${player.location.y} ${player.location.z} minecraft:turtle_egg replace air`);
}
function wardenSonicboomAbility(player) {
  const wardenSonicDelay = 35;
  player.playSound("mob.warden.sonic_charge", { volume: 1 });
  system.runTimeout(() => {
    for (let i = 2; i < 25; i += 2) {
      const location = Vector3Add(player.getHeadLocation(), Vector3Scalar(player.getViewDirection(), i));
      player.dimension.spawnParticle("minecraft:sonic_explosion", location);
      const entities = player.dimension.getEntities({
        location,
        maxDistance: 3
      });
      const targets = entities.filter((target) => target.id !== player.id);
      targets.forEach((target) => {
        target.applyDamage(12);
      });
    }
    player.playSound("mob.warden.sonic_boom", { volume: 1 });
  }, wardenSonicDelay);
}
function witherSkullAbility(player) {
  player.playSound("mob.wither.shoot", { volume: 1 });
  shootProjectileAbility(player, "wither_skull", 1.2);
}
export {
  centerBlockMorph,
  endermanAttemptTeleport,
  runOnAttackAbilities,
  runOnInteractAbilities,
  runPassiveAbilities,
  stopCenterBlockMorph
};
