import {
  world,
  system,
  MolangVariableMap,
  BlockPermutation,
  Player,
} from "@minecraft/server";
const excludeBlocks = [
  "minecraft:chest",
  "minecraft:trapped_chest",
  "minecraft:end_portal_frame",
  "minecraft:air",
  "minecraft:barrel",
  "minecraft:barrier",
  "minecraft:flowing_water",
  "minecraft:obsidian",
  "minecraft:bedrock",
  "minecraft:dragon_egg",
  "minecraft:command_block",
  "minecraft:structure_block",
  "minecraft:repeating_command_block",
  "minecraft:chain_command_block",
  "minecraft:structure_void",
  "minecraft:light_block",
  "minecraft:end_portal",
  "minecraft:water",
  "tvf_randev:black_hole_in_bottle",
  "tvf_randev:vacuum_bottle",
  "tvf_randev:black_hole_tnt",
  "tvf_randev:dark_matter_block",
  "tvf_randev:meteorite_block",
  "tvf_randev:meteorite_ore",
];
const excludeFamilies = [
  "decor",
  "npc",
  "black_hole",
  "tornado",
  "technical",
  "dragon",
  "wither",
];
const needBlocks = ["tvf_randev:vacuum_bottle"];
function blackHole_magnet(dimension) {
  system.runInterval(() => {
    dimension
      .getEntities({
        type: "tvf_randev:black_hole",
      })
      .forEach((ent) => {
        if (!ent.getProperty("property:absorbed")) {
          let blackHoleLocation = ent.location;
          let age = ent.getProperty("property:age");
          let maxRadius = 15 + age * 0.2;
          let killRadius = (1 + age * 0.1) * 0.5;
          //Теперь не преследует игрока
          //blackHole_follow_player(ent)
          for (const mob of dimension.getEntities({
            location: blackHoleLocation,
            maxDistance: maxRadius,
            excludeFamilies: excludeFamilies,
            excludeNames: ["Vacuum Bottle"],
          })) {
            if (!mob.isValid) break;
            const startLocation = mob.location;
            const vector = {
              x: blackHoleLocation.x - startLocation.x,
              y: blackHoleLocation.y - startLocation.y,
              z: blackHoleLocation.z - startLocation.z,
            };
            const vector_length = Math.sqrt(
              vector.x * vector.x + vector.y * vector.y + vector.z * vector.z
            );
            if (vector_length < killRadius) {
              //mob.clearVelocity()
              mob.kill();
              break;
            }
            let force =
              (maxRadius - vector_length) *
              (maxRadius - vector_length) *
              (1.0 / (maxRadius - killRadius) / (maxRadius - killRadius));
            const vector_norm = {
              x: vector.x / vector_length,
              y: vector.y / vector_length,
              z: vector.z / vector_length,
            };
            if (mob instanceof Player) {
              if (mob.getGameMode() == "Creative") break;
              mob.applyKnockback(
                {
                  x: vector_norm.x * force,
                  z: vector_norm.z * force,
                },
                vector_norm.y * force
              );
            } else {
              mob.applyImpulse({
                x: vector_norm.x * force,
                y: vector_norm.y * force,
                z: vector_norm.z * force,
              });
            }
          }
        }
      });
  }, 1);
}
function blackHole_age(dimension) {
  system.runInterval(() => {
    dimension
      .getEntities({
        type: "tvf_randev:black_hole",
      })
      .forEach((ent) => {
        const age = ent.getProperty("property:age");
        if (age < 100) {
          ent.setProperty("property:age", age + 1);
          ent.getComponent("minecraft:health").setCurrentValue(100 - age);
        } else killing(ent);
      });
  }, 100);
}
function blackHole_griefing(dimension) {
  system.runInterval(() => {
    dimension
      .getEntities({
        type: "tvf_randev:black_hole",
      })
      .forEach((ent) => {
        const center = ent.location;
        const blockPerm = BlockPermutation.resolve("air");
        const maxBlockBreak = 20;
        let waitMax = 1000;
        system.runJob(
          (function* () {
            let i = 0;
            let temp = 0;
            for (let blockCounter = 0; blockCounter < maxBlockBreak; ) {
              if (blockCounter == temp) i++;
              else i = 0;
              if (i > waitMax) {
                break;
              }
              temp = blockCounter;
              const random_r = Math.random() * 20;
              const random_tet = Math.random() * 180;
              const random_phi = Math.random() * 180;
              const location_sphere = sphere(random_r, random_tet, random_phi);
              let location = {
                x: center.x + location_sphere.x,
                y: center.y + location_sphere.y,
                z: center.z + location_sphere.z,
              };
              location = {
                x: ~~location.x,
                y: ~~location.y,
                z: ~~location.z,
              };
              const block = dimension.getBlock(location);
              if (block == undefined) continue;
              //if (needBlocks.includes(block.typeId)) killing(ent)
              if (excludeBlocks.includes(block.typeId)) continue;
              if (!excludeBlocks.includes(block.above(1).typeId)) continue;
              block.setPermutation(blockPerm);
              let map = new MolangVariableMap();
              map.setFloat("x", center.x - location.x);
              map.setFloat("y", center.y - location.y);
              map.setFloat("z", center.z - location.z);
              dimension.spawnParticle(
                "tvf_randev:black_hole_broke_block",
                location,
                map
              );
              blockCounter++;
              if (blockCounter > maxBlockBreak) break;
              yield;
            }
          })()
        );
      });
  }, 10);
}
function blackHole_visual(dimension) {
  system.runInterval(() => {
    dimension
      .getEntities({
        type: "tvf_randev:black_hole",
      })
      .forEach((ent) => {
        let map = new MolangVariableMap();
        const biome_type = ent.getProperty("property:biome_type");
        let biome_variant = 0; // normal
        if (biome_type == "desert") biome_variant = 1;
        else if (biome_type == "snow") biome_variant = 2;
        else if (biome_type == "water") biome_variant = 3;
        else if (dimension.id == "minecraft:nether") biome_variant = 4;
        else if (dimension.id == "minecraft:the_end") biome_variant = 5;

        map.setFloat("biome_variant", biome_variant);
        try {
          dimension.spawnParticle(
            "tvf_randev:black_hole_block_spiral",
            ent.location,
            map
          );
        } catch {}
      });
  }, 5);
}
// close
world.afterEvents.playerPlaceBlock.subscribe((event) => {
  if (needBlocks.includes(event.block.typeId)) {
    const dimension = event.dimension;
    const blockLocation = event.block.location;
    const block = event.block;
    const ent = dimension.getEntities({
      type: "tvf_randev:black_hole",
      location: blockLocation,
      maxDistance: 20,
      closest: 1,
    });
    if (ent.length == 1) {
      const hole = ent[0];
      if (!hole.getProperty("property:absorbed")) {
        hole.setProperty("property:absorbed", true);
        const b = block.location;
        const a = hole.location;
        const vec = {
          x: b.x - a.x,
          y: b.y - a.y,
          z: b.z - a.z,
        };
        let map = new MolangVariableMap();
        map.setFloat("x", vec.x + 0.5);
        map.setFloat("y", vec.y + 0.5);
        map.setFloat("z", vec.z + 0.5);
        dimension.playSound("beacon.ambient", b);
        const id = system.runInterval(() => {
          if (hole.getProperty("property:absorbed")) {
            dimension.spawnParticle("tvf_randev:black_hole_absorb", a, map);
          }
        }, 1);
        const id_finally = system.runTimeout(() => {
          system.clearRun(id);
          if (hole.getProperty("property:absorbed")) {
            world.sendMessage({
              translate: "tvf_randev.vacuum_bottle.message.black_hole_caught",
            });
            block.setPermutation(
              BlockPermutation.resolve("tvf_randev:black_hole_in_bottle")
            );
            dimension.playSound("beacon.activate", b);
            //dimension.spawnParticle("minecraft:crop_growth_area_emitter", blockLocation)
            killing(hole);
          }
        }, 20 * 5);
        const id_looking_for = system.runInterval(() => {
          if (dimension.getBlock(b).typeId != "tvf_randev:vacuum_bottle") {
            hole.setProperty("property:absorbed", false);
            system.clearRun(id);
            system.clearRun(id_looking_for);
            system.clearRun(id_finally);
          }
        }, 1);
      }
    }
  }
});
//--------------------------------------------------------------------------------------------------------------
function sphere(r, tet, phi) {
  let dec = {
    x: r * Math.sin(tet) * Math.cos(phi),
    y: r * Math.sin(tet) * Math.sin(phi),
    z: r * Math.cos(tet),
  };
  return dec;
}
function killing(ent) {
  ent.dimension.createExplosion(ent.location, 3);
  ent.kill();
}
export function blackHole_MAIN(dimensions) {
  for (const dimension of dimensions) {
    blackHole_magnet(dimension);
    blackHole_age(dimension);
    blackHole_griefing(dimension);
    blackHole_visual(dimension);
  }
}
