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

const notValid = [
  // This add-on
  "pb_gat:grappling_hook_projectile",
  "pb_gat:mb_gam_lever_entity",
  "pb_gat:mb_gam_entity",
  "pb_gat:flight_dummy",
  "pb_gat:mb_tinker_table_entity",
  "pb_gat:mb_tt_item_entity",
  "pb_gat:mb_up_item_entity",
  "pb_gat:mb_upgrade_puncher_entity",
  "pb_gat:shockwave_projectile",
  "pb_gat:spike_dummy",
  "pb_gat:torch_projectile",
  "pb_gat:withered_arrow_dummy",
  // Vanilla
  "minecraft:area_effect_cloud",
  "minecraft:arrow",
  "minecraft:breeze_wind_charge_projectile",
  "minecraft:dragon_fireball",
  "minecraft:egg",
  "minecraft:ender_crystal",
  "minecraft:ender_dragon",
  "minecraft:ender_pearl",
  "minecraft:eye_of_ender_signal",
  "minecraft:fireball",
  "minecraft:fireworks_rocket",
  "minecraft:fishing_hook",
  "minecraft:lightning_bolt",
  "minecraft:lingering_potion",
  "minecraft:llama_spit",
  "minecraft:npc",
  "minecraft:ominous_item_spawner",
  "minecraft:shulker_bullet",
  "minecraft:small_fireball",
  "minecraft:snowball",
  "minecraft:splash_potion",
  "minecraft:thrown_trident",
  "minecraft:tripod_camera",
  "minecraft:wind_charge_projectile",
  "minecraft:wither_skull_dangerous",
  "minecraft:wither_skull",
  "minecraft:wither",
  "minecraft:xp_bottle",
];

// Map of playerId → list of held entities
export const heldEntities = new Map(); // { playerId: [{ entity, distance, hasForce, hasPower }] }

export function handleGauntlet(player, item) {
  const playerId = player.id;

  // If already holding something, release them
  if (heldEntities.has(playerId)) {
    const heldList = heldEntities.get(playerId);
    const view = player.getViewDirection();

    for (const { entity, hasPower } of heldList) {
      if (hasPower && entity?.isValid()) {
        const impulse = {
          x: view.x * 1.5,
          y: view.y * 1.5,
          z: view.z * 1.5,
        };
        entity.applyImpulse(impulse);
      }
    }

    player.playSound("mob.endermen.portal", {
      volume: 1,
      pitch: 1.6,
      location: player.location,
    });
    player.sendMessage("§a->§r Entity released.");

    heldEntities.delete(playerId);
    return;
  }

  // Read upgrades
  const contents =
    new ItemInventoryContents(item).getContainer()?.content ?? [];

  const hasReach = contents.some(
    (stack) => stack?.typeId === "pb_gat:orb_reach"
  );
  const hasForce = contents.some(
    (stack) => stack?.typeId === "pb_gat:orb_force"
  );
  const hasPower = contents.some(
    (stack) => stack?.typeId === "pb_gat:orb_power"
  );
  const hasExtra = contents.some(
    (stack) => stack?.typeId === "pb_gat:orb_extra"
  );
  const hasEmber = contents.some(
    (stack) => stack?.typeId === "pb_gat:orb_ember"
  );

  const maxDistance = hasReach ? 24 : 12;
  const maxTargets = hasExtra ? 3 : 1;

  const headLoc = player.getHeadLocation();
  const viewDir = player.getViewDirection();
  const step = 1;

  let collected = [];

  for (
    let i = 0;
    i <= maxDistance && collected.length < maxTargets;
    i += step
  ) {
    const sample = {
      x: headLoc.x + viewDir.x * i,
      y: headLoc.y + viewDir.y * i,
      z: headLoc.z + viewDir.z * i,
    };

    const mobs = player.dimension.getEntities({
      location: sample,
      maxDistance: 1.5,
    });

    for (const mob of mobs) {
      if (mob.id === player.id) continue;
      if (notValid.includes(mob.typeId)) continue;
      if (collected.find((e) => e.entity.id === mob.id)) continue; // Prevent duplicates

      const dist = Math.sqrt(
        Math.pow(headLoc.x - mob.location.x, 2) +
          Math.pow(headLoc.y - mob.location.y, 2) +
          Math.pow(headLoc.z - mob.location.z, 2)
      );

      collected.push({
        entity: mob,
        distance: Math.max(dist, 6),
        hasForce,
        hasPower,
        hasEmber,
      });

      if (collected.length >= maxTargets) break;
    }
  }

  if (collected.length > 0) {
    heldEntities.set(player.id, collected);

    // play "grab success" sound
    player.playSound("mob.endermen.portal", {
      volume: 1,
      pitch: 0.9,
      location: player.location,
    });
    player.sendMessage("§a->§r Entity succesfully picked up.");
  } else {
    // play "failed grab" sound
    player.playSound("note.bass", {
      volume: 1,
      pitch: 0.6,
      location: player.location,
    });
    player.sendMessage("§4->§r No entities in range.");
  }
}

system.runInterval(() => {
  for (const [playerId, heldList] of heldEntities.entries()) {
    const player = world.getAllPlayers().find((p) => p.id === playerId);

    // Cleanup if player is missing
    if (!player?.isValid()) {
      heldEntities.delete(playerId);
      continue;
    }

    const equippable = player.getComponent("equippable");
    const heldItem = equippable.getEquipmentSlot("Mainhand")?.getItem();

    if (!heldItem || heldItem.typeId !== "pb_gat:gadget_gauntlet") {
      heldEntities.delete(playerId); // Drop all mobs if gauntlet is unequipped
      continue;
    }

    const head = player.getHeadLocation();
    const dir = player.getViewDirection();
    const dim = player.dimension;

    // Track if any entities were released due to being invalid
    let removedEntities = false;

    for (const mobData of [...heldList]) {
      const { entity, distance, hasForce } = mobData;

      if (!entity?.isValid()) {
        // Entity died or was removed → release it
        removedEntities = true;
        heldList.splice(heldList.indexOf(mobData), 1);
        continue;
      }

      const current = entity.location;
      const intended = {
        x: head.x + dir.x * distance,
        y: head.y + dir.y * distance,
        z: head.z + dir.z * distance,
      };

      const safe = { ...current }; // Start with current position
      const rounded = {
        x: Math.floor(intended.x),
        y: Math.floor(intended.y),
        z: Math.floor(intended.z),
      };

      // X-axis check
      try {
        const blockX = dim.getBlock({
          x: rounded.x,
          y: Math.floor(current.y),
          z: Math.floor(current.z),
        });
        if (blockX?.typeId === "minecraft:air") {
          safe.x = intended.x;
        }
      } catch {}

      // Y-axis check (try up to +3 in case of floor issues)
      for (let dy = 0; dy <= 3; dy++) {
        try {
          const blockY = dim.getBlock({
            x: Math.floor(safe.x),
            y: rounded.y + dy,
            z: Math.floor(safe.z),
          });
          if (blockY?.typeId === "minecraft:air") {
            safe.y = intended.y + dy;
            break;
          }
        } catch {}
      }

      // Z-axis check
      try {
        const blockZ = dim.getBlock({
          x: Math.floor(safe.x),
          y: Math.floor(safe.y),
          z: rounded.z,
        });
        if (blockZ?.typeId === "minecraft:air") {
          safe.z = intended.z;
        }
      } catch {}

      // Teleport to adjusted safe position
      entity.teleport(safe, { facingLocation: player.location });

      if (mobData.hasEmber && entity.typeId !== "minecraft:item") {
        entity.setOnFire(1);
      }
      if (hasForce && entity.typeId !== "minecraft:item") {
        entity.applyDamage(1);
      }
      try {
        dim.spawnParticle("pb_gat:pearl_teleport", entity.location);
      } catch {}
    }

    // If all held entities are gone, release the player
    if (heldList.length === 0) {
      heldEntities.delete(playerId);
    }

    // If we removed any, tell the player
    if (removedEntities) {
      player.sendMessage("§c->§r The held entity has perished or vanished.");
    }
  }
}, 1);

