import { system, world, EquipmentSlot, GameMode } from "@minecraft/server";
import { randomKnockback } from "./knockbacks";

const excludeFromHealthDisplay = ["hb_hr:guide_book", "hb_hr:banned_wither_skull_podest_b1", "hb_hr:banned_wither_skull_podest_b2", "hb_hr:banned_wither_skull_podest_b3"];

const monsterFamilies = ["screamer", "lost_soul", "scared_chicken", "scared_cow", "scared_pig", "scared_sheep", "hb_hr:banned_wither", "death_moth", "arthropod", "blaze", "bogged", "breeze", "cavespider", "dragon", "endermite", "ghast", "guardian", "guardian_elder", "hoglin", "hoglin_adult", "hoglin_baby", "hoglin_huntable", "magmacube", "monster", "phantom", "shulker", "skeleton", "skeletonhorse", "slime", "spider", "stray", "undead", "vex", "warden", "wither", "zoglin", "zoglin_adult", "zoglin_baby", "zombiehorse", "zombie"];

// ✅ Global persistent map
const playerTargetMap = new Map();

export function vindicatorChestplate(player) {
  const mainHand = player.getComponent("equippable")?.getEquipment(EquipmentSlot.Mainhand);
  if (mainHand?.typeId === "hb_hr:blood_moon_clock") {
    playerTargetMap.delete(player.id);
    player.runCommand(`title @s actionbar `); // Clear actionbar
    return;
  }

  const playerEquipment = player.getComponent("equippable");
  const chestplate = playerEquipment.getEquipment(EquipmentSlot.Chest);

  if (!chestplate || chestplate.typeId !== "hb_hr:enforced_vindicator_chestplate") {
    playerTargetMap.delete(player.id);
    return;
  }

  const nearbyEntities = player.getEntitiesFromViewDirection({
    minDistance: 0,
    maxDistance: 64,
    location: player.location,
  });

  if (nearbyEntities.length > 0) {
    const entity = nearbyEntities[0].entity;

    const currentId = entity.id;
    const lastTarget = playerTargetMap.get(player.id);

    if (!lastTarget || lastTarget.id !== currentId) {
      playerTargetMap.set(player.id, {
        id: currentId,
        entity: entity,
        tickCount: 0,
      });
    } else {
      lastTarget.tickCount = 0;
    }

    healthDisplay(player, entity);
  } else {
    const lastTarget = playerTargetMap.get(player.id);
    if (lastTarget) {
      const entity = lastTarget.entity;

      if (!entity.isValid()) {
        playerTargetMap.delete(player.id);
        return;
      }

      lastTarget.tickCount += 1;

      if (lastTarget.tickCount >= 60) {
        playerTargetMap.delete(player.id);
        return;
      }

      healthDisplay(player, entity);
    }
  }
}

function healthDisplay(player, raycastEntity) {
  const comp = raycastEntity.getComponent("health");
  if (!comp || excludeFromHealthDisplay.includes(raycastEntity.typeId)) return;

  const filledBars = comp.currentValue;
  const emptyBars = comp.effectiveMax;

  const rawName = raycastEntity.nameTag ? raycastEntity.nameTag.split(`\n`)[0] : raycastEntity.typeId;

  const formattedName = formatEntityName(rawName);
  calculateHealthSetColors(player, raycastEntity, formattedName, emptyBars, filledBars);
}

function calculateHealthSetColors(player, entity, text, maxHealth, currentHealth) {
  if (entity.typeId === "minecraft:npc") {
    currentHealth = maxHealth = 1;
  } else if (currentHealth > maxHealth) {
    [currentHealth, maxHealth] = [maxHealth, currentHealth];
  }

  const percentage = (currentHealth / maxHealth) * 100;
  const currentHearts = roundToTwoDecimalAndRemove(currentHealth / 2);

  let color = "§4";
  if (percentage === 100) color = "§2";
  else if (percentage >= 75) color = "§a";
  else if (percentage >= 50) color = "§e";
  else if (percentage >= 30) color = "§6";
  else if (percentage >= 10) color = "§c";

  // const displayedText = `${text} ${color}§l${currentHearts}§r `.replace(/ {2,}/g, " ");
  if (entity.typeId.includes("minecraft:")) {
    player.runCommand(`/titleraw @s actionbar {"rawtext":[{"translate":"entity.` + entity.typeId.replace("minecraft:", "") + `.name"},{"text":" ` + color + `§l` + currentHearts + `§r "}]}`);
  } else {
    player.runCommand(`/titleraw @s actionbar {"rawtext":[{"translate":"entity.` + entity.typeId + `.name"},{"text":" ` + color + `§l` + currentHearts + `§r "}]}`);
  }
}

function formatEntityName(name) {
  const cleaned = name
    .replace(/[^:]*:/g, "")
    .replace(/_+/g, " ")
    .replace(/v2/i, "");

  return cleaned
    .trim()
    .split(" ")
    .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
    .join(" ");
}
function roundToTwoDecimalAndRemove(zahl) {
  var roundedNumber = parseFloat(zahl).toFixed(1);
  return roundedNumber % 1 === 0 ? parseInt(roundedNumber) : roundedNumber;
}

export function screamingHelmet(player) {
  let playerEquipment = player.getComponent("equippable");
  const helmet = playerEquipment.getEquipment(EquipmentSlot.Head);
  if (helmet === undefined) return;
  if (helmet.typeId == "hb_hr:screaming_helmet") {
    const nearbyEntities = world.getDimension(player.dimension.id).getEntities({
      maxDistance: 4,
      location: player.location,
      excludeTypes: ["minecraft:player", "minecraft:item", "minecraft:falling_block", "minecraft:xp_orb", "minecraft:arrow"],
    });
    let particleFlag = false;
    if (nearbyEntities[0] == undefined || nearbyEntities.length == 0) return;
    else {
      nearbyEntities.forEach((hit_entity) => {
        let entityFamilyComponent = hit_entity.getComponent("type_family");
        if (!entityFamilyComponent) return;
        let entityFamilies = entityFamilyComponent.getTypeFamilies();
        entityFamilies.forEach((family) => {
          if (monsterFamilies.includes(family)) {
            particleFlag = true;
            let randomDamage = Math.random() * 3 + 1;
            hit_entity.applyDamage(randomDamage, { cause: "entityAttack", damagingEntity: player });
            randomKnockback(hit_entity, player, 1, 1.2);
          }
        });
      });
      if (particleFlag) {
        try {
          player.dimension.spawnParticle("hb_hr:screamer_helmet_shockwave", player.getHeadLocation());
        } catch (error) {}
      }
    }
  }
}

export function lostLeggings(player) {
  let playerEquipment = player.getComponent("equippable");
  const leggings = playerEquipment.getEquipment(EquipmentSlot.Legs);
  if (leggings === undefined) return;
  if (leggings.typeId == "hb_hr:lost_leggings") {
    player.addEffect("speed", 60, { amplifier: 1, showParticles: false });
  }
}
export function deathWingBoots(player) {
  let playerEquipment = player.getComponent("equippable");

  if (player.getGameMode() === GameMode.creative) return;
  const boot = playerEquipment.getEquipment(EquipmentSlot.Feet);
  if (boot === undefined) return;
  if (boot.typeId == "hb_hr:death_wing_boots") {
    let maxJumps = 1;
    // Initialize the variables jumpCount and lastJumping
    let coyoteTime = player.getDynamicProperty("hb_hr:coyoteTime") || 0;

    if (player.isOnGround || player.isInWater) {
      // Landing: reset the timer
      player.setDynamicProperty("hb_hr:coyoteTime", 0);
      coyoteTime = 0;
    } else {
      // In the air: increment the timer by 1
      coyoteTime++;
      player.setDynamicProperty("hb_hr:coyoteTime", coyoteTime);
    }

    // After 10 ticks in the air: apply Slow-Falling effect
    if (coyoteTime >= 15 && !player.isOnGround && !player.isInWater && !player.isGliding) {
      player.addEffect("slow_falling", 20, { amplifier: 0, showParticles: false });
    }
    if (player.isOnGround) {
      player.jumpCount = 0; // Reset the jump counter when the player touches the ground
      player.lastJumping = false; // Reset the last jump status
      player.setDynamicProperty("hb_hr:jumpsRemaining", maxJumps); // Set the remaining jumps based on the tier
      player.addTag("canDoublejump"); // Allow the double jump when the player touches the ground
      return;
    }

    // If the player is in the air and has not jumped yet
    if (player.isJumping && !player.lastJumping && !player.isOnGround) {
      player.jumpCount++; // Increase the jump counter
      // // ////world.sendMessage(`Jump Count: ${player.jumpCount}`); // Output the current jump counter (optional)
    }

    // Trigger for the first additional jump (only if the player hasn't jumped before)
    let remainingJumps = player.getDynamicProperty("hb_hr:jumpsRemaining");

    if (remainingJumps > 0 && player.isJumping && player.hasTag("canDoublejump") && !player.lastJumping && player.jumpCount === 2) {
      // Execute the first additional jump
      // // ////world.sendMessage("JUMP NEW"); // Message for the additional jump
      player.applyKnockback(0, 0, 0, 1); // Execute the additional jump (knockback values can be adjusted)
      try {
        player.dimension.spawnParticle("hb_hr:double_jump", player.location); // Particle effect for the additional jump (optional)
      } catch (error) {}
      player.dimension.playSound("hb_hr:double_jump", player.location);
      // Decrease the remaining jumps
      player.setDynamicProperty("hb_hr:jumpsRemaining", remainingJumps - 1);

      // If no jumps are remaining, remove the tag and reset everything
      if (remainingJumps - 1 <= 0) {
        player.removeTag("canDoublejump"); // Disable the additional jump when no jumps are left
      }
    }

    // Trigger for further additional jumps (after the first one)
    if (remainingJumps > 0 && player.isJumping && player.hasTag("canDoublejump") && player.jumpCount > 2 && !player.lastJumping) {
      // Execute another additional jump
      // // ////world.sendMessage("JUMP NEW (Further)"); // Message for another additional jump
      player.applyKnockback(0, 0, 0, 1); // Execute the additional jump (knockback values can be adjusted)

      try {
        player.dimension.spawnParticle("hb_hr:double_jump", player.location); // Particle effect for the additional jump (optional)
      } catch (error) {}

      player.dimension.playSound("hb_hr:double_jump", player.location);

      // Decrease the remaining jumps
      player.setDynamicProperty("hb_hr:jumpsRemaining", remainingJumps - 1);

      // If no jumps are remaining, remove the tag and reset everything
      if (remainingJumps - 1 <= 0) {
        player.removeTag("canDoublejump"); // Disable further jumps when no jumps are left
      }
    }

    // Reset jump status when the player stops jumping
    if (!player.isJumping) {
      player.lastJumping = false; // The player has stopped jumping
    } else {
      player.lastJumping = true; // The player is jumping
    }

    // When the player touches the ground, reset everything
    if (player.isOnGround) {
      player.setDynamicProperty("hb_hr:jumpsRemaining", maxJumps); // Reset the remaining jumps
      player.jumpCount = 0; // Reset the jump counter
      player.addTag("canDoublejump"); // Allow another additional jump
      player.lastJumping = false; // Reset the jump status when the player touches the ground
    }
  }
}
