import { world, system } from "@minecraft/server";
import { ItemInventoryContents } from "../utilities.js";

const glidingPlayers = new WeakSet();
const launchCooldowns = new WeakMap();
const doubleJumpBoosted = new WeakSet();

system.runInterval(() => {
  const dimensions = ["overworld", "nether", "the_end"];

  const players = dimensions.flatMap((dim) =>
    world.getDimension(dim).getEntities({ type: "minecraft:player" })
  );

  players.forEach((player) => {
    const equippable = player.getComponent("equippable");
    const heldItem = equippable.getEquipmentSlot("Mainhand")?.getItem();

    if (heldItem?.typeId !== "pb_gat:gadget_glider") {
      glidingPlayers.delete(player);
      launchCooldowns.delete(player);
      return;
    }

    const pos = player.location;
    const dimension = player.dimension;

    const currentBlock = dimension.getBlock({
      x: Math.floor(pos.x),
      y: Math.floor(pos.y),
      z: Math.floor(pos.z),
    });

    const blockBelow = dimension.getBlock({
      x: Math.floor(pos.x),
      y: Math.floor(pos.y - 1.3),
      z: Math.floor(pos.z),
    });

    if (
      player.isOnGround ||
      currentBlock?.typeId === "minecraft:water" ||
      currentBlock?.typeId === "minecraft:lava"
    ) {
      glidingPlayers.delete(player);
      launchCooldowns.delete(player);
      player.removeTag("pb_gat.double_jump_triggered");
      return;
    }

    if (blockBelow?.typeId !== "minecraft:air") {
      glidingPlayers.delete(player);
      launchCooldowns.delete(player);
      return;
    }

    const tags = player.getTags();

    if (
      tags.includes("pb_gat_trinket_infinity_cube") ||
      tags.includes("pb_gat_trinket_pocket_universe")
    ) {
      glidingPlayers.delete(player);
      launchCooldowns.delete(player);
      return;
    }

    const hasTriggeredDoubleJump = tags.includes(
      "pb_gat.double_jump_triggered"
    );

    // Allow glide if falling and either:
    // - They don't have double jump
    // - Or they do, and have already triggered it
    if (!glidingPlayers.has(player)) {
      if (tags.includes("pb_gat:has_double_jump") && !hasTriggeredDoubleJump) {
        return;
      }
    }

    const vel = player.getVelocity();
    if (vel?.y >= 0) {
      return; // still rising
    }

    const isLaunching = !glidingPlayers.has(player);
    if (isLaunching) {
      glidingPlayers.add(player);

      if (hasTriggeredDoubleJump) {
        player.removeTag("pb_gat.double_jump_triggered");
        doubleJumpBoosted.add(player);
      }
    }

    const cooldown = launchCooldowns.get(player);
    if (cooldown !== undefined) {
      if (cooldown > 0) {
        launchCooldowns.set(player, cooldown - 1);
        return;
      } else {
        launchCooldowns.delete(player);

        if (doubleJumpBoosted.has(player)) {
          doubleJumpBoosted.delete(player);

          const yaw = (player.getRotation().y * Math.PI) / 180;
          const knockbackX = -Math.sin(yaw);
          const knockbackZ = Math.cos(yaw);

          player.applyKnockback(knockbackX, knockbackZ, 1.2, 0); // horizontal push
        }
      }
    }

    const result = new ItemInventoryContents(heldItem).getContainer();
    const contents = result?.content ?? [];

    const hasSpeedUpgrade = contents.some(
      (stack) => stack?.typeId === "pb_gat:orb_speed"
    );
    const hasLiftUpgrade = contents.some(
      (stack) => stack?.typeId === "pb_gat:orb_life"
    );

    const speedBoost = hasSpeedUpgrade ? 0.85 : 0.45;
    const downwardForce = hasLiftUpgrade ? 0.03 : 0.06;

    const yaw = (player.getRotation().y * Math.PI) / 180;
    const knockbackX = -Math.sin(yaw);
    const knockbackZ = Math.cos(yaw);

    player.applyKnockback(knockbackX, knockbackZ, speedBoost, -downwardForce);

    player.playAnimation("animation.pb_gat.player.cancel_run_glide", {
      blendOutTime: 0,
      stopExpression:
        "q.is_on_ground || !q.is_item_name_any('slot.weapon.mainhand','pb_gat:gadget_glider')",
      controller: `controller_name1`,
    });

    player.playAnimation(
      "animation.pb_gat.player.first_person_cancel_run_glide",
      {
        blendOutTime: 0,
        stopExpression:
          "q.is_on_ground || !q.is_item_name_any('slot.weapon.mainhand','pb_gat:gadget_glider')",
        controller: `controller_name2`,
      }
    );

    player.addEffect("slow_falling", 10, {
      showParticles: false,
    });
  });
});
