import { world, system, BlockPermutation, EquipmentSlot, EntityComponentTypes, ItemStack } from "@minecraft/server";
import showDialogueOnItemUse from "./util/show-dialogue-on-item-use";
import { NAMESPACE } from "./constants";
import {
  goodMobs,
  evilMobs,
  goodEquipment,
  evilEquipment,
  evilChestplates,
  goodChestplates,
  RandomNames_bat,
  RandomNames_hound,
  RandomNames_pig,
  RandomNames_rat,
  RandomNames_stag,
  RandomNames_wolf,
  RandomNames_steed,
  RandomNames_fox,
} from "./variables";
import { TIER1MAX, TIER2MAX, TIER3MAX, TIERPARAGONMAX } from "./constants";
import goodStaffAbility from "./weapons/goodStaffAbility.js";
import evilStaffAbility from "./weapons/evilStaffAbility.js";
import goodJump from "./armour/goodJump.js";
import evilJump from "./armour/evilJump.js";
import intro_good from "./intro/good.js";
import intro_evil from "./intro/evil.js";
import { getCinematicActive } from "./state.js";
import goodDaggerAbility from "./weapons/goodDaggerAbility.js";
import evilDaggerAbility from "./weapons/evilDaggerAbility.js";
import goodGreatAxeAbility from "./weapons/goodGreatAxeAbility.js";
import evilGreatAxeAbility from "./weapons/evilGreatAxeAbility.js";
import goodSpearAbility from "./weapons/goodSpearAbility.js";
import evilSpearAbility from "./weapons/evilSpearAbility.js";
import goodShieldAbility from "./weapons/goodShieldAbility.js";
import evilShieldAbility from "./weapons/evilShieldAbility.js";
import goodSwordAbility from "./weapons/goodSwordAbility.js";
import evilSwordAbility from "./weapons/evilSwordAbility.js";
import { evilHubRemove } from "./hubs/evil.js";
import { goodHubRemove } from "./hubs/good.js";
import goodLeggingsAbility from "./armour/goodLeggingsAbility.js";
import evilLeggingsAbility from "./armour/evilLeggingsAbility.js";
import goodBootsAbility from "./armour/goodBootsAbility.js";
import evilBootsAbility from "./armour/evilBootsAbility.js";
import altarSequence from "./altars/sequence.js";
import { goodHubSummon } from "./hubs/good.js";
import { evilHubSummon } from "./hubs/evil.js";
import showsettings from "./util/showsettings";
import * as Good from "./xp/good.js";
import * as Evil from "./xp/evil.js";

// Constants and Maps
const playerVelocities = new Map();
const abilityCooldowns = new Map();
const jumpCooldowns = new Map();
const sneakingPlayers = new Map();
const sprintingPlayers = new Map();
const playerVillagerInteraction = new Map();
export const altarSequencePlayers = new Map();
const leggingsCooldowns = new Map();
const leggingsDurations = {
  good: [4000, 6000, 8000], // Durations for good leggings by tier
  evil: [4000, 6000, 8000], // Durations for evil leggings by tier
};
const weaponCooldowns = {
  "float_ad:good_sword": 8000,
  "float_ad:evil_sword": 8000,
  "float_ad:good_dagger": 5000,
  "float_ad:evil_dagger": 5000,
  "float_ad:good_great_axe": 10000,
  "float_ad:evil_great_axe": 10000,
  "float_ad:good_spear": 7000,
  "float_ad:evil_spear": 7000,
  "float_ad:good_staff": 9000,
  "float_ad:evil_staff": 9000,
};

let tickMinute = 800;
let tickRound = 0;
let playerArray = undefined;

// Event: Player join
world.afterEvents.playerJoin.subscribe((event) => {
  system.runTimeout(() => {
    const player = world.getPlayers().find((p) => p.name === event.playerName);

    if (player) {
      Good.initializePlayerData(player);
      Evil.initializePlayerData(player);
      initializePlayerJumpTracking(player);
    } else {
      console.error(`Player with name ${event.playerName} could not be found after delay.`);
    }
  }, 250); // Delay of 200ms

  system.runTimeout(() => {
    const player = world.getPlayers().find((p) => p.name === event.playerName);

    if (player) {
      if (player.hasTag("good_hub")) {
        goodHubRemove(player);
      } else if (player.hasTag("evil_hub")) {
        evilHubRemove(player);
      }
    }
  }, 100); // Delay of 4 second
});

// Event: Player spawn
world.afterEvents.playerSpawn.subscribe((event) => {
  const player = event.player;
  if (event.initialSpawn) {
    initializePlayerJumpTracking(player);
    const tags = player.getTags();
    const hasGoodXPTag = tags.some((tag) => tag.startsWith("goodXP_"));
    const hasEvilXPTag = tags.some((tag) => tag.startsWith("evilXP_"));

    if (!hasGoodXPTag) {
      Good.goodXP.set(player.id, 0);
    }
    if (!hasEvilXPTag) {
      Evil.evilXP.set(player.id, 0);
    }

    player.addTag(player.id.toString());
  } else {
    Good.clearTrackCheck(player.id);
    Evil.clearTrackCheck(player.id);
  }

  if (!player.hasTag("has_float_ad_book")) {
    player.runCommandAsync("function fs/ad/init");
    spawnIntroNPC(player);
  }
});
// Function: Spawn Intro NPC
function spawnIntroNPC(player) {
  try {
    const structureName = "float_ad/intro_npc";

    system.runTimeout(() => {
      const playerCheck = [...world.getPlayers()].find((p) => p.id === player.id);
      if (!playerCheck) return;

      const viewDirection = player.getRotation();
      const radians = (viewDirection.y + 90) * (Math.PI / 180); // Adjusted to locate in front of the player
      const startX = player.location.x + Math.cos(radians) * 3;
      const startY = player.location.y;
      const startZ = player.location.z + Math.sin(radians) * 3;

      const loadCommand = `structure load "${structureName}" ${startX} ${startY + 1} ${startZ}`;

      const playerDimension = player.dimension;
      const blockAbove = playerDimension.getBlock({ x: startX, y: startY, z: startZ });
      const blockBelow = playerDimension.getBlock({ x: startX, y: startY - 1, z: startZ });

      if (blockAbove.typeId === "minecraft:air" && blockBelow.typeId !== "minecraft:air") {
        playerDimension.runCommand(loadCommand);
        return;
      }

      for (let dx = -3; dx <= 3; dx++) {
        for (let dz = -3; dz <= 3; dz++) {
          const x = player.location.x + dx;
          const y = player.location.y;
          const z = player.location.z + dz;
          const blockAbove = playerDimension.getBlock({ x: x, y: y, z: z });
          const blockBelow = playerDimension.getBlock({ x: x, y: y - 1, z: z });
          if (blockAbove.typeId === "minecraft:air" && blockBelow.typeId !== "minecraft:air") {
            const loadCommand2 = `structure load "${structureName}" ${x} ${y + 1} ${z}`;
            playerDimension.runCommand(loadCommand2);
            player.runCommand(`playsound float_ad.level_up_evil @a ${x} ${y} ${z}`);
            return;
          }
        }
      }
    }, 150); // Delay of 150ms to ensure the player is in the game
  } catch {
    console.error(`Error spawning intro NPC for ${player.name}.`);
  }
}

// Event: Entity spawn
world.afterEvents.entitySpawn.subscribe((entityEvent) => {
  if (entityEvent && entityEvent.entity && entityEvent.entity.typeId == NAMESPACE + ":tracker") {
    const spawnLocation = entityEvent.entity.location;
    const { entity } = entityEvent;
    const LocalPlayer = world.getDimension("overworld").getEntities({
      type: "minecraft:player",
      maxDistance: 0,
      location: spawnLocation,
    });
    if (LocalPlayer.length > 0) {
      Good.awaitUpdate(entity, LocalPlayer[0]);
      Evil.awaitUpdate(entity, LocalPlayer[0]);
    }
  }
});

// Event: Data-driven entity trigger
world.afterEvents.dataDrivenEntityTrigger.subscribe((event) => {
  let tempPlayer,
    adjustment = undefined;
  adjustment = 0;
  if (event.eventId.indexOf(`float_ad:trigger`) != -1) {
    tempPlayer = players.get(Good.reverseGoodXPChecks.get(event.entity.id));
    if (affiliation(tempPlayer) === "good") {
      Good.clearTrackCheck(Good.reverseGoodXPChecks.get(event.entity.id));
      try {
        //adjustment = Good.entityPower(tempPlayer.dimension, tempPlayer.location);
      } catch {
        //adjustment = 0;
      }
      Good.progress(tempPlayer, adjustment);
    } else if (affiliation(tempPlayer) === "evil") {
      Evil.clearTrackCheck(Evil.reverseEvilXPChecks.get(event.entity.id));
      try {
        //adjustment = Good.entityPower(tempPlayer.dimension, tempPlayer.location);
      } catch {
        //adjustment = 0;
      }
      Evil.progress(tempPlayer, adjustment);
    }
  }
});

// Initialize player jump tracking
function initializePlayerJumpTracking(player) {
  if (!playerVelocities.has(player.id)) {
    playerVelocities.set(player.id, { prevYVelocity: 0 });
  }
}

system.runInterval(() => {
  playerArray = world.getAllPlayers();

  playerArray.forEach((player) => {
    affiliationCheck(player);
  });
}, 10);

// Event: Entity die
world.afterEvents.entityDie.subscribe((event) => {
  let tempPlayer,
    adjustment = undefined;
  adjustment = 0;
  const deadEntity = event.deadEntity;
  const damagingEntity = event.damageSource.damagingEntity;

  if (damagingEntity) {
    tempPlayer = [...world.getPlayers()].find((player) => player.id === damagingEntity.id);
    if (tempPlayer) {
      if (affiliation(tempPlayer) === "good") {
        Good.mobKilled(deadEntity.typeId, deadEntity.location, tempPlayer, deadEntity);
      } else if (affiliation(tempPlayer) === "evil") {
        Evil.mobKilled(deadEntity.typeId, deadEntity.location, tempPlayer, deadEntity);
      }
    }
  } else if (event.damageSource.cause === "starve") {
    const nearbyPlayers = world.getDimension("overworld").getEntities({
      type: "minecraft:player",
      maxDistance: 20,
      location: deadEntity.location,
    });

    if (nearbyPlayers.length > 0) {
      const nearestPlayer = nearbyPlayers.reduce(
        (nearest, player) => {
          const distance = Math.sqrt(
            Math.pow(player.location.x - deadEntity.location.x, 2) +
              Math.pow(player.location.y - deadEntity.location.y, 2) +
              Math.pow(player.location.z - deadEntity.location.z, 2)
          );
          return distance < nearest.distance ? { player, distance } : nearest;
        },
        { player: null, distance: Infinity }
      ).player;

      if (nearestPlayer) {
        if (affiliation(nearestPlayer) === "good") {
          Good.mobKilled(deadEntity.typeId, deadEntity.location, nearestPlayer, deadEntity);
        } else if (affiliation(nearestPlayer) === "evil") {
          Evil.mobKilled(deadEntity.typeId, deadEntity.location, nearestPlayer, deadEntity);
        }
      }
    }
  }
});

// Event: Player interact with entity
world.afterEvents.playerInteractWithEntity.subscribe((event) => {
  const { player, target } = event;

  if (event.target.typeId === "minecraft:villager_v2") {
    playerVillagerInteraction.set(player.id, true);
    system.runTimeout(() => {
      playerVillagerInteraction.set(player.id, false);
    }, 300); // 10 seconds
  }
});

// Interval: Track player jumps
system.runInterval(() => {
  world.getPlayers().forEach((player) => {
    const velocity = player.getVelocity();
    const playerData = playerVelocities.get(player.id);

    if (!playerData) {
      initializePlayerJumpTracking(player);
      return;
    }

    if (playerData.prevYVelocity <= 0 && velocity.y > 0 && player.isJumping) {
      const now = Date.now(); // Current time in milliseconds
      const lastJumpTime = jumpCooldowns.get(player.id) || 0;

      // Cooldown: Ensure at least 1 second (1000 ms) has passed since the last jump
      if (now - lastJumpTime < 1000) {
        return; // Exit if the cooldown has not expired
      }

      // Update the last jump time
      jumpCooldowns.set(player.id, now);

      // Determine player's affiliation and tier
      const affiliationType = affiliation(player);
      const currentTier =
        affiliationType === "good"
          ? Good.goodTier.get(player.id) || 1
          : affiliationType === "evil"
          ? Evil.evilTier.get(player.id) || 1
          : 0;

      // Check for correct tier and chestplate
      if (currentTier >= 1) {
        if (affiliationType === "good" && hasCorrectChestplate(player, goodChestplates)) {
          goodJump(player, currentTier);
        } else if (affiliationType === "evil" && hasCorrectChestplate(player, evilChestplates)) {
          evilJump(player, currentTier);
        }
      }
    }

    playerData.prevYVelocity = velocity.y;
  });
}, 1);

// Apply Lore to Equipped Items
system.runInterval(() => {
  // Get all player armor slots, Head, Chest, Legs, Feet, and apply lore to them
  world.getPlayers().forEach((player) => {
    const equipment = player.getComponent(EntityComponentTypes.Equippable);
    if (!equipment) return;
    const armorSlots = [EquipmentSlot.Head, EquipmentSlot.Chest, EquipmentSlot.Legs, EquipmentSlot.Feet];

    armorSlots.forEach((slot) => {
      const item = equipment.getEquipment(slot);
      if (item && item.typeId.startsWith("float_ad:")) {
        if (!item.getLore() || item.getLore().length === 0) {
          let lore;
          switch (slot) {
            case EquipmentSlot.Head:
              const affiliationType = affiliation(player);
              if (affiliationType === "good") {
                lore = [`Laurel - §8Allows Angel abilities to be used`];
              } else if (affiliationType === "evil") {
                lore = [`§7Horns - §8Allows Demon abilities to be used`];
              } else {
                lore = [``];
              }
              break;
            case EquipmentSlot.Chest:
              lore = ["§7Wing Flap - §8Jump to activate"];
              break;
            case EquipmentSlot.Legs:
              lore = ["§7Invulnerability - §8When hit, gain bubble hearts"];
              break;
            case EquipmentSlot.Feet:
              lore = ["§7Speed boost - §8Sprint to activate"];
              break;
            default:
              lore = [""];
          }
          // Create a new item stack with the same item and lore
          const newItem = new ItemStack(item.typeId, item.amount);
          newItem.setLore(lore);
          equipment.setEquipment(slot, newItem);
        }
      }
    });
  });
}, 20);

// Check player affiliation for armor slots
system.runInterval(() => {
  world.getPlayers().forEach((player) => {
    const equipment = player.getComponent(EntityComponentTypes.Equippable);
    if (!equipment) return;

    const affiliationType = affiliation(player);
    const armorSlots = [EquipmentSlot.Chest, EquipmentSlot.Legs, EquipmentSlot.Feet];

    armorSlots.forEach((slot) => {
      const item = equipment.getEquipment(slot);
      if (item && item.typeId.startsWith("float_ad:")) {
        const isGoodItem = item.typeId.includes("good");
        const isEvilItem = item.typeId.includes("evil");

        if ((isGoodItem && affiliationType !== "good") || (isEvilItem && affiliationType !== "evil")) {
          // Move item to inventory if affiliation does not match
          const inventory = player.getComponent("minecraft:inventory").container;
          for (let i = 0; i < inventory.size; i++) {
            if (!inventory.getItem(i)) {
              inventory.setItem(i, item);
              equipment.setEquipment(slot, new ItemStack("minecraft:air", 1));
              if (affiliationType === "evil") {
                player.sendMessage(`§cOnly Angels can equip good armor.`);
              } else if (affiliationType === "good") {
                player.sendMessage(`§cOnly Demons can equip evil armor.`);
              } else {
                player.sendMessage(`§cYou must choose a side to equip this armor.`);
              }
              break;
            }
          }
        }
      }
    });
  });
}, 20);

// Interval: Track player sneaking
system.runInterval(() => {
  const players = world.getPlayers();

  players.forEach((player) => {
    const playerId = player.id;

    if (player.isSneaking) {
      if (!sneakingPlayers.has(playerId)) {
        // Start tracking the sneaking time
        sneakingPlayers.set(playerId, Date.now());
        // Immediately apply the shield ability
        const affiliationType = affiliation(player);
        const currentTier =
          affiliationType === "good"
            ? Good.goodTier.get(playerId) || 1
            : affiliationType === "evil"
            ? Evil.evilTier.get(playerId) || 1
            : 0;

        const equipment = player.getComponent(EntityComponentTypes.Equippable);
        if (!equipment) {
          return;
        }

        const mainHandItem = equipment.getEquipment(EquipmentSlot.Mainhand);
        const offHandItem = equipment.getEquipment(EquipmentSlot.Offhand);

        // Check for correct tier and shield
        if (currentTier >= 1) {
          if (
            affiliationType === "good" &&
            (mainHandItem?.typeId === "float_ad:good_shield" || offHandItem?.typeId === "float_ad:good_shield")
          ) {
            goodShieldAbility(player, currentTier);
          } else if (
            affiliationType === "evil" &&
            (mainHandItem?.typeId === "float_ad:evil_shield" || offHandItem?.typeId === "float_ad:evil_shield")
          ) {
            evilShieldAbility(player, currentTier);
          }
        }
      }
    } else {
      // Remove from sneakingPlayers if the player stops sneaking
      sneakingPlayers.delete(playerId);
      // Immediately stop the shield ability
      evilShieldAbility(player, 0); // Pass 0 to indicate stopping the ability
    }
  });
}, 1);

// Interval: Track player sprinting
system.runInterval(() => {
  const players = world.getPlayers();

  players.forEach((player) => {
    const playerId = player.id;

    if (player.isSprinting) {
      if (!sprintingPlayers.has(playerId)) {
        // Start tracking the sprinting time
        sprintingPlayers.set(playerId, Date.now());
      }

      const affiliationType = affiliation(player);
      const currentTier =
        affiliationType === "good"
          ? Good.goodTier.get(playerId) || 1
          : affiliationType === "evil"
          ? Evil.evilTier.get(playerId) || 1
          : 0;

      const equipment = player.getComponent(EntityComponentTypes.Equippable);
      if (!equipment) {
        return;
      }

      const boots = equipment.getEquipment(EquipmentSlot.Feet);
      if (!boots) {
        return;
      }

      // Check for correct boots regardless of tier
      if (affiliationType === "good" && boots.typeId.startsWith("float_ad:good_")) {
        goodBootsAbility(player, currentTier);
      } else if (affiliationType === "evil" && boots.typeId.startsWith("float_ad:evil_")) {
        evilBootsAbility(player, currentTier);
      }
    } else {
      // Remove effects if the player stops sprinting
      if (sprintingPlayers.has(playerId)) {
        player.runCommandAsync(`effect "${player.name}" clear speed`);
        sprintingPlayers.delete(playerId);
      }
    }
  });
}, 5);

// Check if player has correct chestplate
function hasCorrectChestplate(player, chestplateMap) {
  const equipment = player.getComponent(EntityComponentTypes.Equippable);
  if (!equipment) {
    return false;
  }

  const chestplate = equipment.getEquipment(EquipmentSlot.Chest);
  if (!chestplate) {
    return false;
  }

  return chestplateMap.includes(chestplate.typeId);
}

// Get cooldown for item type
function getCooldown(itemTypeId) {
  return weaponCooldowns[itemTypeId] || 8000; // Default cooldown of 8 seconds if not specified
}

// Event: Item use
world.afterEvents.itemUse.subscribe((event) => {
  const { source: player, itemStack: item } = event;
  if (!player || !item) return;

  const now = Date.now(); // Get current time in milliseconds
  const playerCooldowns = abilityCooldowns.get(player.id) || {};
  const lastUsed = playerCooldowns[item.typeId] || 0;
  const cooldown = getCooldown(item.typeId);

  // Check cooldown
  if (now - lastUsed < cooldown) {
    if (item.typeId.startsWith("float_ad:")) {
      const remaining = ((cooldown - (now - lastUsed)) / 1000).toFixed(1); // Calculate remaining time
      player.sendMessage(`§cAbility on cooldown! ${remaining}s remaining.`);
    }
    return; // Exit if still on cooldown
  }

  // Define the player's current tier based on affiliation
  const affiliationType = affiliation(player);
  let currentTier = 0;

  if (affiliationType === "good") {
    currentTier = Good.goodTier.get(player.id) || 1; // Default to Tier 1 if not set
  } else if (affiliationType === "evil") {
    currentTier = Evil.evilTier.get(player.id) || 1; // Default to Tier 1 if not set
  }

  if (item.typeId === "float_ad:good_hub_pearl") {
    if (affiliationType === "good") {
      if (now - lastUsed >= cooldown) {
        if (player.hasTag("evil_hub")) {
          player.sendMessage(`§cYou cannot use this item while in the Evil Hub!`);
        } else if (!player.hasTag("good_hub")) {
          goodHubSummon(player);
          playerCooldowns[item.typeId] = now; // Update cooldown time
          abilityCooldowns.set(player.id, playerCooldowns);
        } else {
          goodHubRemove(player);
          playerCooldowns[item.typeId] = now; // Update cooldown time
          abilityCooldowns.set(player.id, playerCooldowns);
        }
      } else {
        const remaining = ((cooldown - (now - lastUsed)) / 1000).toFixed(1); // Calculate remaining time
        player.sendMessage(`§cAbility on cooldown! ${remaining}s remaining.`);
      }
    } else {
      player.sendMessage(`§cYou must be Good to use this item!`);
    }
  } else if (item.typeId === "float_ad:evil_hub_pearl") {
    if (affiliationType === "evil") {
      if (now - lastUsed >= cooldown) {
        if (player.hasTag("good_hub")) {
          player.sendMessage(`§cYou cannot use this item while in the Good Hub!`);
        } else if (!player.hasTag("evil_hub")) {
          evilHubSummon(player);
          playerCooldowns[item.typeId] = now; // Update cooldown time
          abilityCooldowns.set(player.id, playerCooldowns);
        } else {
          evilHubRemove(player);
          playerCooldowns[item.typeId] = now; // Update cooldown time
          abilityCooldowns.set(player.id, playerCooldowns);
        }
      } else {
        const remaining = ((cooldown - (now - lastUsed)) / 1000).toFixed(1); // Calculate remaining time
        player.sendMessage(`§cAbility on cooldown! ${remaining}s remaining.`);
      }
    } else {
      player.sendMessage(`§cYou must be Evil to use this item!`);
    }
  }

  // Check for item usage and tier restriction
  if (item.typeId === "float_ad:good_staff") {
    if (currentTier >= 1) {
      goodStaffAbility(player, currentTier);
      playerCooldowns[item.typeId] = now; // Update cooldown time
      abilityCooldowns.set(player.id, playerCooldowns);
    } else {
      player.sendMessage(`§cYou must reach Tier 1 to use this ability!`);
    }
  } else if (item.typeId === "float_ad:evil_staff") {
    if (currentTier >= 1) {
      evilStaffAbility(player, currentTier);
      playerCooldowns[item.typeId] = now; // Update cooldown time
      abilityCooldowns.set(player.id, playerCooldowns);
    } else {
      player.sendMessage(`§cYou must reach Tier 1 to use this ability!`);
    }
  } else if (item.typeId === "float_ad:good_dagger") {
    if (currentTier >= 1) {
      goodDaggerAbility(player, currentTier);
      playerCooldowns[item.typeId] = now; // Update cooldown time
      abilityCooldowns.set(player.id, playerCooldowns);
    } else {
      player.sendMessage(`§cYou must reach Tier 1 to use this ability!`);
    }
  } else if (item.typeId === "float_ad:evil_dagger") {
    if (currentTier >= 1) {
      evilDaggerAbility(player, currentTier);
      playerCooldowns[item.typeId] = now; // Update cooldown time
      abilityCooldowns.set(player.id, playerCooldowns);
    } else {
      player.sendMessage(`§cYou must reach Tier 1 to use this ability!`);
    }
  } else if (item.typeId === "float_ad:good_great_axe") {
    if (currentTier >= 1) {
      goodGreatAxeAbility(player, currentTier);
      playerCooldowns[item.typeId] = now; // Update cooldown time
      abilityCooldowns.set(player.id, playerCooldowns);
    } else {
      player.sendMessage(`§cYou must reach Tier 1 to use this ability!`);
    }
  } else if (item.typeId === "float_ad:evil_great_axe") {
    if (currentTier >= 1) {
      evilGreatAxeAbility(player, currentTier);
      playerCooldowns[item.typeId] = now; // Update cooldown time
      abilityCooldowns.set(player.id, playerCooldowns);
    } else {
      player.sendMessage(`§cYou must reach Tier 1 to use this ability!`);
    }
  } else if (item.typeId === "float_ad:good_spear") {
    if (currentTier >= 1) {
      goodSpearAbility(player, currentTier);
      playerCooldowns[item.typeId] = now; // Update cooldown time
      abilityCooldowns.set(player.id, playerCooldowns);
    } else {
      player.sendMessage(`§cYou must reach Tier 1 to use this ability!`);
    }
  } else if (item.typeId === "float_ad:evil_spear") {
    if (currentTier >= 1) {
      evilSpearAbility(player, currentTier);
      playerCooldowns[item.typeId] = now; // Update cooldown time
      abilityCooldowns.set(player.id, playerCooldowns);
    } else {
      player.sendMessage(`§cYou must reach Tier 1 to use this ability!`);
    }
  } else if (item.typeId === "float_ad:good_sword") {
    if (currentTier >= 1) {
      goodSwordAbility(player, currentTier);
      playerCooldowns[item.typeId] = now; // Update cooldown time
      abilityCooldowns.set(player.id, playerCooldowns);
    } else {
      player.sendMessage(`§cYou must reach Tier 1 to use this ability!`);
    }
  } else if (item.typeId === "float_ad:evil_sword") {
    if (currentTier >= 1) {
      evilSwordAbility(player, currentTier);
      playerCooldowns[item.typeId] = now; // Update cooldown time
      abilityCooldowns.set(player.id, playerCooldowns);
    } else {
      player.sendMessage(`§cYou must reach Tier 1 to use this ability!`);
    }
  }
});

let previousInventories = new Map();
let playerXP = new Map();

// Interval: Main game loop
system.runInterval(() => {
  tickMinute++;
  tickRound++;
  if (tickRound > 20) {
    tickRound = 0;
    playerArray = world.getAllPlayers();

    playerArray.forEach((player) => {
      if (tickMinute > 1200) {
        tickMinute = 0;
      } else {
        const currentXP = player.getTotalXp();

        // Check for Villager Trade
        if (playerXP.has(player.id)) {
          const previousXP = playerXP.get(player.id);
          if (currentXP > previousXP && playerVillagerInteraction.get(player.id)) {
            if (affiliation(player) === "good") {
              playerVillagerInteraction.set(player.id, false);
              Good.progress(player, 10);
              player.runCommand(
                `particle float_ad:xp_gain_10 ${player.location.x + 1} ${player.location.y + 1} ${player.location.z}`
              );
            } else if (affiliation(player) === "evil") {
              playerVillagerInteraction.set(player.id, false);
              Evil.progress(player, -5);
              player.runCommand(
                `particle float_ad:xp_drain_5 ${player.location.x + 1} ${player.location.y + 1} ${player.location.z}`
              );
            }
          }
        }
        playerXP.set(player.id, currentXP);

        const affiliationType = affiliation(player);

        // ENTITY PLAYER HOSTILE CHECKS
        const nearbyEntities = player.dimension.getEntities({
          location: player.location,
          maxDistance: 36,
        });

        nearbyEntities.forEach((entity) => {
          if (affiliationType === "good") {
            if (evilMobs.includes(entity.typeId)) {
              entity.runCommand("event entity @s float_ad:player_hostile");
            } else if (goodMobs.includes(entity.typeId)) {
              entity.runCommand("event entity @s float_ad:player_not_hostile");
            } else if (entity.typeId === "float_ad:elemental_golem" || entity.typeId === "float_ad:wisp") {
              const state = entity.getProperty("float_ad:state");
              if (state === 2) {
                // Evil state
                entity.runCommand("event entity @s float_ad:player_hostile");
              } else if (state === 1) {
                // Good state
                entity.runCommand("event entity @s float_ad:player_not_hostile");
              }
            }
          } else if (affiliationType === "evil") {
            if (goodMobs.includes(entity.typeId)) {
              entity.runCommand("event entity @s float_ad:player_hostile");
            } else if (evilMobs.includes(entity.typeId)) {
              entity.runCommand("event entity @s float_ad:player_not_hostile");
            } else if (entity.typeId === "float_ad:elemental_golem" || entity.typeId === "float_ad:wisp") {
              const state = entity.getProperty("float_ad:state");
              if (state === 1) {
                // Good state
                entity.runCommand("event entity @s float_ad:player_hostile");
              } else if (state === 2) {
                // Evil state
                entity.runCommand("event entity @s float_ad:player_not_hostile");
              }
            }
          }
        });

        if (affiliationType === "good" || affiliationType === "evil") {
          const currentTier =
            affiliationType === "good" ? Good.goodTier.get(player.id) || 1 : Evil.evilTier.get(player.id) || 1;

          // Determine the expected helmet and XP cap based on the player's current tier
          let expectedHelmet, currentXP, maxXP;
          if (affiliationType === "good") {
            expectedHelmet =
              currentTier === 1 ? "float_ad:good_2_helmet" : currentTier === 2 ? "float_ad:good_3_helmet" : null;
            currentXP = Good.goodXP.get(player.id) || 0;
            maxXP =
              currentTier === 1
                ? TIER1MAX
                : currentTier === 2
                ? TIER2MAX
                : currentTier === 3
                ? TIER3MAX
                : TIERPARAGONMAX;
          } else if (affiliationType === "evil") {
            expectedHelmet =
              currentTier === 1 ? "float_ad:evil_2_helmet" : currentTier === 2 ? "float_ad:evil_3_helmet" : null;
            currentXP = Evil.evilXP.get(player.id) || 0;
            maxXP =
              currentTier === 1
                ? TIER1MAX
                : currentTier === 2
                ? TIER2MAX
                : currentTier === 3
                ? TIER3MAX
                : TIERPARAGONMAX;
          }

          // Check if the player has met the requirements to upgrade their tier
          const playerEquipment = player.getComponent(EntityComponentTypes.Equippable);
          const equippedHelmet = playerEquipment.getEquipment(EquipmentSlot.Head);
          if (equippedHelmet && equippedHelmet.typeId === expectedHelmet && currentXP >= maxXP) {
            if (affiliationType === "good") {
              Good.upgradePlayerTier(player);
              player.sendMessage(`§aCongratulations! You have leveled up to Angel tier ${currentTier + 1}.`);
            } else if (affiliationType === "evil") {
              Evil.upgradePlayerTier(player);
              player.sendMessage(`§cCongratulations! You have leveled up to Demon tier ${currentTier + 1}.`);
            }
          }

          // Check if the player has equipped the expected helmet and if XP is at the cap
          if (player.hasTag("show_xp_bar") && !getCinematicActive()) {
            const affiliationType = affiliation(player);

            if (affiliationType === "good") {
              const xp = Good.goodXP.get(player.id) || 0;
              const currentTier = Good.goodTier.get(player.id) || 1;
              const maxXP = currentTier === 1 ? TIER1MAX : currentTier === 2 ? TIER2MAX : TIER3MAX;

              // Always display the XP bar
              Good.displayGoodXP(player, xp);

              // Check for higher-tier helmet warning
              const playerEquipment = player.getComponent(EntityComponentTypes.Equippable);
              const equippedHelmet = playerEquipment.getEquipment(EquipmentSlot.Head);
              if (equippedHelmet) {
                const helmetId = equippedHelmet.typeId;

                if (
                  (helmetId === "float_ad:good_2_helmet" && currentTier < 2) ||
                  (helmetId === "float_ad:good_3_helmet" && currentTier < 3)
                ) {
                  if (xp < maxXP) {
                    player.onScreenDisplay.setActionBar(`§cYou need more XP before using this Laurel`);
                  }
                }
              }
            } else if (affiliationType === "evil") {
              const xp = Evil.evilXP.get(player.id) || 0;
              const currentTier = Evil.evilTier.get(player.id) || 1;
              const maxXP = currentTier === 1 ? TIER1MAX : currentTier === 2 ? TIER2MAX : TIER3MAX;

              // Always display the XP bar
              Evil.displayEvilXP(player, xp);

              // Check for higher-tier helmet warning
              const playerEquipment = player.getComponent(EntityComponentTypes.Equippable);
              const equippedHelmet = playerEquipment.getEquipment(EquipmentSlot.Head);
              if (equippedHelmet) {
                const helmetId = equippedHelmet.typeId;

                if (
                  (helmetId === "float_ad:evil_2_helmet" && currentTier < 2) ||
                  (helmetId === "float_ad:evil_3_helmet" && currentTier < 3)
                ) {
                  if (xp < maxXP) {
                    player.onScreenDisplay.setActionBar(`§cYou need more XP before using these Horns`);
                  }
                }
              }
            } else {
              console.error("Player is Neutral");
            }
          }
        }
      }
    });
  }
});

// Check player affiliation
function affiliationCheck(player) {
  const playerEquipment = player.getComponent(EntityComponentTypes.Equippable);
  const equippedHelmet = playerEquipment.getEquipment(EquipmentSlot.Head);
  if (equippedHelmet != undefined) {
    const equippedId = equippedHelmet.typeId;
    if (goodEquipment.includes(equippedId)) {
      switchGood(player);
    } else if (evilEquipment.includes(equippedId)) {
      switchEvil(player);
    } else {
      switchNeutral(player);
    }
  } else {
    switchNeutral(player);
  }
}

// Get player affiliation
function affiliation(player) {
  if (player.hasTag("good")) {
    return "good";
  } else if (player.hasTag("evil")) {
    return "evil";
  } else {
    return "neutral";
  }
}

// Switch player to good affiliation
function switchGood(player) {
  player.removeTag("evil");
  player.removeTag("neutral");
  player.addTag("good");
}

// Switch player to evil affiliation
function switchEvil(player) {
  player.removeTag("good");
  player.removeTag("neutral");
  player.addTag("evil");
}

// Switch player to neutral affiliation
function switchNeutral(player) {
  player.removeTag("evil");
  player.removeTag("good");
  player.addTag("neutral");
}

// Check if player has item in inventory
function hasItemInInventory(player, itemId) {
  try {
    const inventory = player.getComponent("minecraft:inventory");
    if (!inventory) return false;

    for (let i = 0; i < inventory.container.size; i++) {
      const item = inventory.container.getItem(i);
      if (item && item.typeId === itemId) {
        return true; // Item is found in inventory
      }
    }
  } catch (error) {
    console.error(`Error checking inventory: ${error}`);
  }
  return false; // Item not found
}

// Event: Player break block
world.afterEvents.playerBreakBlock.subscribe(handleAfterPlayerBreak);

// Handle player break block
function handleAfterPlayerBreak(event) {
  if (event.brokenBlockPermutation.matches("float_ad:altar")) {
    const player = event.player;
    player.runCommand("event entity @e[type=float_ad:altar_wisp,r=10] float_ad:kill_entity");
  }
}

// BLOCK COMPONENT REGISTRRY EVENTS

var newPermutation = undefined;

world.afterEvents.playerInteractWithBlock.subscribe((event) => {
  const blockId = event.block.typeId;
  if (blockId === "float_ad:good_anvil" || blockId === "float_ad:evil_anvil") {
    let upgradetotier = 1;
    const affiliationType = affiliation(event.player);
    const currentTier =
      affiliationType === "good" ? Good.goodTier.get(event.player.id) || 1 : Evil.evilTier.get(event.player.id) || 1;
    const xp =
      affiliationType === "good" ? Good.goodXP.get(event.player.id) || 0 : Evil.evilXP.get(event.player.id) || 0;

    if (currentTier >= 3 || xp == TIER2MAX) {
      upgradetotier = 3;
    } else if (xp == TIER1MAX) {
      upgradetotier = 2;
    } else {
      return;
    }

    const direction = event.block.permutation.getState("minecraft:cardinal_direction");
    if (upgradetotier == 3 && event.block.permutation.getState("float_ad:powered") != 2) {
      newPermutation = BlockPermutation.resolve(event.block.typeId, {
        "float_ad:powered": 2,
        "minecraft:cardinal_direction": direction,
      });
      event.block.setPermutation(newPermutation);
    } else if (upgradetotier == 2 && event.block.permutation.getState("float_ad:powered") != 1) {
      newPermutation = BlockPermutation.resolve(event.block.typeId, {
        "float_ad:powered": 1,
        "minecraft:cardinal_direction": direction,
      });
      event.block.setPermutation(newPermutation);
    } else {
      return;
    }
  } else {
    return;
  }
});

// Event: World initialize
world.beforeEvents.worldInitialize.subscribe((event) => {
  event.blockComponentRegistry.registerCustomComponent("float_ad:on_interact_anvil", {
    onPlayerInteract(e) {
      const blockId = e.block.typeId;
      if (blockId === "float_ad:good_anvil" || blockId === "float_ad:evil_anvil") {
        let upgradetotier = 1;
        const goodXP = Good.goodXP.get(e.player.id) || 0;
        console.error(`${goodXP}`);
        if (goodXP == TIER2MAX) {
          upgradetotier = 3;
        } else if (goodXP == TIER1MAX) {
          upgradetotier = 2;
        } else {
          return;
        }
        console.error(` upgrade ${upgradetotier}`);

        const direction = e.block.permutation.getState("minecraft:cardinal_direction");
        if (upgradetotier == 3 && e.block.permutation.getState("float_ad:powered") != 2) {
          newPermutation = BlockPermutation.resolve(e.block.typeId, {
            "float_ad:powered": 2,
            "minecraft:cardinal_direction": direction,
          });
          e.block.setPermutation(newPermutation);
        } else if (upgradetotier == 2 && e.block.permutation.getState("float_ad:powered") != 1) {
          newPermutation = BlockPermutation.resolve(e.block.typeId, {
            "float_ad:powered": 1,
            "minecraft:cardinal_direction": direction,
          });
          e.block.setPermutation(newPermutation);
        } else {
          return;
        }
      } else {
        return;
      }
    },
  });
  event.blockComponentRegistry.registerCustomComponent("float_ad:on_place_altar", {
    onPlace(e) {
      if (e.block.typeId === "float_ad:altar") {
        const blockLocation = e.block.location;
        const dimension = e.block.dimension;
        const spawnLocation = {
          x: Math.floor(blockLocation.x) + 0.5,
          y: Math.floor(blockLocation.y) + 0.2,
          z: Math.floor(blockLocation.z) + 0.5,
        };
        dimension.spawnEntity("float_ad:altar_wisp", spawnLocation);
        dimension.runCommand("event entity @e[type=float_ad:altar_wisp,r=10] float_ad:set_neutral");
      }
    },
  });
  //Starting Altar Interaction
  event.blockComponentRegistry.registerCustomComponent("float_ad:on_interact_altar", {
    onPlayerInteract(e) {
      if (affiliation(e.player) === "neutral") {
        return;
      }
      const blockId = e.block.typeId;
      const structureType = e.block.permutation.getState("float_ad:type");
      const broken = e.block.permutation.getState("float_ad:broken");
      const sequence = e.block.permutation.getState("float_ad:sequence");
      const isGoodAltar = e.block.permutation.getState("float_ad:good");
      const isEvilAltar = e.block.permutation.getState("float_ad:evil");
      const playerAffiliation = affiliation(e.player);

      if (blockId === "float_ad:altar" && !broken && !sequence) {
        if (isGoodAltar && playerAffiliation === "good") {
          return; // Do nothing if the altar is good and the player is good
        } else if (isEvilAltar && playerAffiliation === "evil") {
          return; // Do nothing if the altar is evil and the player is evil
        } else {
          // Pass additional information to the altar sequence
          const conflict =
            (isGoodAltar && playerAffiliation === "evil") || (isEvilAltar && playerAffiliation === "good");
          altarSequence(playerAffiliation, structureType, e.block, e.player, conflict);
        }
      } else {
        return;
      }
    },
  });
});

world.afterEvents.entitySpawn.subscribe((event) => {
  const entity = event.entity;
  if (entity.typeId === "minecraft:slime") {
    return; // Do nothing if the entity is a slime
  }
  if (event.cause === "Born") {
    const nearbyPlayers = entity.dimension.getEntities({
      type: "minecraft:player",
      maxDistance: 10,
      location: entity.location,
    });

    if (nearbyPlayers.length > 0) {
      const nearestPlayer = nearbyPlayers.reduce(
        (nearest, player) => {
          const distance = Math.sqrt(
            Math.pow(player.location.x - entity.location.x, 2) +
              Math.pow(player.location.y - entity.location.y, 2) +
              Math.pow(player.location.z - entity.location.z, 2)
          );
          return distance < nearest.distance ? { player, distance } : nearest;
        },
        { player: null, distance: Infinity }
      ).player;

      if (nearestPlayer) {
        const affiliationType = affiliation(nearestPlayer);
        if (affiliationType === "good" || (affiliationType === "evil" && evilMobs.includes(entity.typeId))) {
          Good.progress(nearestPlayer, 25);
          nearestPlayer.runCommand(
            `particle float_ad:xp_gain_25 ${entity.location.x} ${entity.location.y + 1} ${entity.location.z}`
          );
        } else if (affiliationType === "evil") {
          Evil.progress(nearestPlayer, -10);
          nearestPlayer.runCommand(
            `particle float_ad:xp_drain_10 ${entity.location.x} ${entity.location.y + 1} ${entity.location.z}`
          );
        }
      }
    }
  }
});

world.afterEvents.playerInteractWithEntity.subscribe((event) => {
  const { player, target } = event;
  if (
    target.typeId === "float_ad:celestial_stag" ||
    target.typeId === "float_ad:abyssal_bat" ||
    target.typeId === "float_ad:celestial_wolf" ||
    target.typeId === "float_ad:flying_pig" ||
    target.typeId === "float_ad:nightmare_steed" ||
    target.typeId === "float_ad:plague_rat" ||
    target.typeId === "float_ad:shadow_hound" ||
    target.typeId === "float_ad:spirit_fox"
  ) {
    if (!target.nameTag) {
      const intervalId = system.runInterval(() => {
        if (target.getComponent("minecraft:is_tamed")) {
          let randomNames;
          switch (target.typeId) {
            case "float_ad:spirit_fox":
              randomNames = RandomNames_fox;
              break;
            case "float_ad:celestial_stag":
              randomNames = RandomNames_stag;
              break;
            case "float_ad:abyssal_bat":
              randomNames = RandomNames_bat;
              break;
            case "float_ad:celestial_wolf":
              randomNames = RandomNames_wolf;
              break;
            case "float_ad:flying_pig":
              randomNames = RandomNames_pig;
              break;
            case "float_ad:nightmare_steed":
              randomNames = RandomNames_steed;
              break;
            case "float_ad:plague_rat":
              randomNames = RandomNames_rat;
              break;
            case "float_ad:shadow_hound":
              randomNames = RandomNames_hound;
              break;
            default:
              randomNames = [];
          }
          if (randomNames.length > 0) {
            const randomIndex = Math.floor(Math.random() * randomNames.length);
            const randomName = randomNames[randomIndex];
            target.nameTag = randomName;
          }
          system.clearRun(intervalId);
        }
        if (!player.getComponent("minecraft:riding")) {
          system.clearRun(intervalId);
        }
      }, 10);
    }
  }
});

// Event: Player interact with entity
world.afterEvents.playerInteractWithEntity.subscribe((event) => {
  const { player, target, itemStack } = event;
  const affiliationType = affiliation(player);
  if (target.typeId === "minecraft:cow" && itemStack.typeId === "minecraft:bucket") {
    if (affiliationType === "good") {
      Good.progress(player, 10);
      player.runCommand(
        `particle float_ad:xp_gain_10 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
      );
    } else if (affiliationType === "evil") {
      Evil.progress(player, -5);
      player.runCommand(
        `particle float_ad:xp_drain_5 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
      );
    }
  }
  if (target.typeId === "minecraft:sheep" && itemStack.typeId === "minecraft:shears") {
    if (affiliationType === "good") {
      Good.progress(player, 10);
      player.runCommand(
        `particle float_ad:xp_gain_10 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
      );
    } else if (affiliationType === "evil") {
      Evil.progress(player, -5);
      player.runCommand(
        `particle float_ad:xp_drain_5 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
      );
    }
  }
  if (target.typeId === "minecraft:pig") {
    if (affiliationType === "good") {
      if (itemStack.typeId === "minecraft:saddle") {
        player.runCommand(`summon float_ad:flying_pig ${target.location.x} ${target.location.y} ${target.location.z}`);
        player.runCommand(`event entity @e[type=float_ad:flying_pig,r=10] float_ad:on_saddled`);
      } else {
        player.runCommand(`summon float_ad:flying_pig ${target.location.x} ${target.location.y} ${target.location.z}`);
      }
      target.runCommand("tp @s ~ ~-500 ~");
      player.runCommand(
        `playsound float_ad.pig_transform_flying @a ${target.location.x} ${target.location.y} ${target.location.z}`
      );
      Good.progress(player, 25);
      player.runCommand(
        `particle float_ad:xp_gain_25 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
      );
    } else if (affiliationType === "evil") {
      target.runCommand("event entity @s become_zombie");
      Evil.progress(player, 25);
      player.runCommand(
        `particle float_ad:xp_gain_25 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
      );
    }
  }
  if (target.typeId === "float_ad:celestial_wolf" || target.typeId === "float_ad:spirit_fox") {
    if (target.getComponent("minecraft:is_tamed") && !target.hasTag("xp_awarded")) {
      if (affiliationType === "good") {
        Good.progress(player, 25);
        player.runCommand(
          `particle float_ad:xp_gain_25 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
        );
      } else if (affiliationType === "evil") {
        Evil.progress(player, -10);
        player.runCommand(
          `particle float_ad:xp_drain_10 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
        );
      }
      target.addTag("xp_awarded");
    }
  }
  if (
    target.typeId === "minecraft:wolf" ||
    target.typeId === "minecraft:ocelot" ||
    target.typeId === "minecraft:cat" ||
    target.typeId === "minecraft:parrot" ||
    target.typeId === "minecraft:fox" ||
    target.typeId === "minecraft:camel" ||
    target.typeId === "minecraft:horse"
  ) {
    if (target.getComponent("minecraft:is_tamed") && !target.hasTag("xp_awarded")) {
      if (affiliationType === "good") {
        Good.progress(player, 25);
        player.runCommand(
          `particle float_ad:xp_gain_25 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
        );
      } else if (affiliationType === "evil") {
        Evil.progress(player, -10);
        player.runCommand(
          `particle float_ad:xp_drain_10 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
        );
      }
      target.addTag("xp_awarded");
    }
  } else if (
    target.getComponent("minecraft:is_tamed") &&
    affiliationType === "evil" &&
    evilMobs.includes(target.typeId) &&
    !target.hasTag("xp_awarded")
  ) {
    Evil.progress(player, 25);
    player.runCommand(
      `particle float_ad:xp_gain_25 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
    );
    target.addTag("xp_awarded");
  } else if (
    target.getComponent("minecraft:is_tamed") &&
    affiliationType === "evil" &&
    goodMobs.includes(target.typeId) &&
    !target.hasTag("xp_awarded")
  ) {
    Evil.progress(player, -10);
    player.runCommand(
      `particle float_ad:xp_drain_10 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
    );
    target.addTag("xp_awarded");
  } else if (
    target.getComponent("minecraft:is_tamed") &&
    affiliationType === "good" &&
    goodMobs.includes(target.typeId) &&
    !target.hasTag("xp_awarded")
  ) {
    Good.progress(player, 25);
    player.runCommand(
      `particle float_ad:xp_gain_25 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
    );
    target.addTag("xp_awarded");
  } else if (
    target.getComponent("minecraft:is_tamed") &&
    affiliationType === "good" &&
    evilMobs.includes(target.typeId) &&
    !target.hasTag("xp_awarded")
  ) {
    Good.progress(player, -10);
    player.runCommand(
      `particle float_ad:xpdrain_10 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
    );
    target.addTag("xp_awarded");
  }
  if (target.typeId === "float_ad:wisp" || target.typeId === "float_ad:elemental_golem") {
    const heldItem = player.getComponent(EntityComponentTypes.Equippable).getEquipment(EquipmentSlot.Mainhand);
    if (
      heldItem &&
      (heldItem.typeId === "float_ad:infernal_shard" || heldItem.typeId === "float_ad:crystalised_light")
    ) {
      if (heldItem.typeId === "float_ad:infernal_shard") {
        // Handle interaction with infernal shard
        target.runCommand("event entity @s float_ad:set_evil");
        Evil.progress(player, 50);
        player.runCommand(
          `particle float_ad:xp_gain_25 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
        );
      } else if (heldItem.typeId === "float_ad:crystalised_light") {
        // Handle interaction with crystalised light
        target.runCommand("event entity @s float_ad:set_good");
        Good.progress(player, 50);
        player.runCommand(
          `particle float_ad:xp_gain_50 ${target.location.x} ${target.location.y + 1} ${target.location.z}`
        );
      }
    }
  }
});
// Flying Controller - Control vertical movement based on the facing direction of the player
function flyingControl(player, flyingEntity) {
  const rotation = player.getRotation();
  const pitch = rotation.x * (Math.PI / 180); // Convert pitch to radians

  // Invert the vertical direction based on the player's pitch
  const directionY = -Math.sin(pitch);

  // Calculate the impulse to apply to the flying entity
  const speed = 0.2; // Adjust the speed as needed
  const impulse = {
    x: 0, // No forward movement
    y: directionY * speed,
    z: 0, // No forward movement
  };

  // Apply the impulse to the flying entity
  flyingEntity.applyImpulse(impulse);
}

// ItemUse event for flying entities
world.afterEvents.itemUse.subscribe((event) => {
  const { source: player, itemStack: item } = event;
  if (item.typeId === "minecraft:carrot_on_a_stick" || item.typeId === "minecraft:warped_fungus_on_a_stick") {
    const ridingComponent = player.getComponent("minecraft:riding");
    if (
      ridingComponent &&
      ridingComponent.entityRidingOn &&
      (ridingComponent.entityRidingOn.typeId === "float_ad:flying_pig" ||
        ridingComponent.entityRidingOn.typeId === "float_ad:celestial_wolf" ||
        ridingComponent.entityRidingOn.typeId === "float_ad:abyssal_bat")
    ) {
      // Boost the flying pig's speed or perform some action
      const flyingPig = ridingComponent.entityRidingOn;
      const viewDirection = player.getViewDirection(); // Use player's view direction

      // Calculate the forward impulse based on the player's view direction
      const forwardImpulse = {
        x: viewDirection.x * 0.5, // Adjust the speed as needed
        y: 0,
        z: viewDirection.z * 0.5, // Adjust the speed as needed
      };

      flyingPig.applyImpulse(forwardImpulse);
    }
  }
});

// HUB FUNCTIONALITY + Flying Mechanics
system.runInterval(() => {
  const players = world.getPlayers();

  players.forEach((player) => {
    try {
      const ridingComponent = player.getComponent("minecraft:riding");
      if (ridingComponent.entityRidingOn !== null) {
        const entityType = ridingComponent.entityRidingOn.typeId;
        if (
          entityType === "float_ad:flying_pig" ||
          entityType === "float_ad:abyssal_bat" ||
          entityType === "float_ad:celestial_wolf"
        ) {
          // Player is riding on a flying pig, abyssal bat, or celestial wolf
          flyingControl(player, ridingComponent.entityRidingOn);
        }
      }
    } catch {}
  });

  players.forEach((player) => {
    if (player.hasTag("evil_hub")) {
      evilHubFunctions(player);
    } else if (player.hasTag("good_hub")) {
      goodHubFunctions(player);
    }
  });
}, 5);

function evilHubFunctions(player) {
  const playerLocation = player.location;
  const distance = Math.sqrt(
    Math.pow(playerLocation.x - 57.99, 2) + Math.pow(playerLocation.y - 10.0, 2) + Math.pow(playerLocation.z - 69.1, 2)
  );

  if (distance <= 3) {
    evilHubRemove(player);
  }
}

function goodHubFunctions(player) {
  const playerLocation = player.location;
  const distance = Math.sqrt(
    Math.pow(playerLocation.x - 94, 2) + Math.pow(playerLocation.y - 264, 2) + Math.pow(playerLocation.z - 81, 2)
  );

  if (distance <= 3) {
    goodHubRemove(player);
  }
}

let ow = world.getDimension("overworld");
let tickIndex = 16;
let lastUpdated = 0;
let now = Date.now();
let random = Math.random();
let queryOpts = 0;
let entities = 0;
const minInterval = 550;

const BOOK_ID = "float_ad:guide";
const EVENT_ID = "float_ad:showtranslateui";

// Event: Script event receive
system.afterEvents.scriptEventReceive.subscribe((eventData) => {
  const eventId = eventData.id;
  const sourceEntity = eventData.sourceEntity;

  if (eventId === "float_ad:good_choice") {
    if (!sourceEntity.hasTag("good")) {
      // Handle the good choice event
      intro_good(sourceEntity);
    } else {
      // Despawn the intro NPC if the player is already good
      sourceEntity.sendMessage("You are already good!");
      sourceEntity.runCommandAsync("event entity @e[type=float_ad:intro_npc,r=10] float_ad:despawn");
    }
  } else if (eventId === "float_ad:evil_choice") {
    if (!sourceEntity.hasTag("evil")) {
      // Handle the evil choice event
      intro_evil(sourceEntity);
    } else {
      // Despawn the intro NPC if the player is already evil
      sourceEntity.sendMessage("You are already evil!");
      sourceEntity.runCommandAsync("event entity @e[type=float_ad:intro_npc,r=10] float_ad:despawn");
    }
  }
});

// Event: Show dialogue on item use
system.afterEvents.scriptEventReceive.subscribe(
  showDialogueOnItemUse({
    EventTypeId: EVENT_ID,
    title: {
      translate: "float_ad:guide.name",
    },
    content: {
      rawtext: [
        { translate: "float_ad:info.part_01", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_02", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_03", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_04", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_05", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_06", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_07", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_08", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_09", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_10", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_11", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_12", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_13", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_14", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_15", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_16", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_17", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_18", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_19", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_20", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_21", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_22", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_23", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_24", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_25", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_26", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_27", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_28", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_29", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_30", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_31", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_32", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_33", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_34", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_35", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_36", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_37", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_38", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_39", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_40", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_41", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_42", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_43", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_44", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_45", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_46", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_47", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_48", with: ["\n"] },
        { text: "§r\n\n" },
        { translate: "float_ad:info.part_49", with: ["\n"] },
        { text: "§r\n\n" },
      ],
    },
    exit: {
      translate: "float_ad:guide_exit",
    },
    soundOnOpen: "item.book.page_turn",
    soundOnClose: "item.book.page_turn",
  })
);
// Entity death loot spawns
world.afterEvents.entityDie.subscribe((event) => {
  const killedEntity = event.deadEntity;
  if (killedEntity !== undefined) {
    const entityid = killedEntity.typeId;

    let source = event.damageSource.damagingEntity;
    let sourceTypeId;

    if (source) {
      sourceTypeId = source.typeId;
    }
    if (killedEntity.typeId === "minecraft:player") {
      const playerId = killedEntity.id;
      if (killedEntity.hasTag("book_on_death")) {
        killedEntity.runCommand(`give @s float_ad:book_spawn_egg`);
        const isEvil = killedEntity.hasTag("evil");
        const isGood = killedEntity.hasTag("good");
        if (isEvil || isGood) {
          const itemStack = new ItemStack(isEvil ? "float_ad:evil_hub_pearl" : "float_ad:good_hub_pearl", 1);

          // Add lore to the item
          const itemLore = [
            isEvil ? "§8Use to Teleport to the Demon Hub Realm" : "§8Use to Teleport to the Angel Hub Cloud",
          ];
          itemStack.setLore(itemLore);

          const inventory = killedEntity.getComponent("minecraft:inventory").container;

          // Remove all existing pearls from the inventory
          killedEntity.runCommand(`clear "${killedEntity.name}" float_ad:good_hub_pearl`);
          killedEntity.runCommand(`clear "${killedEntity.name}" float_ad:evil_hub_pearl`);

          // Add the new pearl to the inventory
          inventory.addItem(itemStack);
        }
      }
      if (altarSequencePlayers.has(playerId)) {
        altarSequencePlayers.set(playerId, false);
      }
      if (killedEntity.hasTag("evil_hub")) {
        evilHubRemove(killedEntity);
      } else if (killedEntity.hasTag("good_hub")) {
        goodHubRemove(killedEntity);
      }
    } else {
      try {
        const location = killedEntity.location;
        const locationString = `${Math.floor(location.x)} ${Math.floor(location.y)} ${Math.floor(location.z)}`;
        if (source && source.typeId === "minecraft:player") {
          if (goodMobs.includes(entityid) && affiliation(source) === "evil") {
            world
              .getDimension("overworld")
              .runCommand(`loot spawn ${locationString} loot "float/ad/crystalised_light"`);
          } else if (evilMobs.includes(entityid) && affiliation(source) === "good") {
            world.getDimension("overworld").runCommand(`loot spawn ${locationString} loot "float/ad/infernal_shard"`);
          }
        } else if (event.damageSource.cause === "starve") {
          const nearbyPlayers = world.getDimension("overworld").getEntities({
            type: "minecraft:player",
            maxDistance: 20,
            location: killedEntity.location,
          });

          if (nearbyPlayers.length > 0) {
            const nearestPlayer = nearbyPlayers.reduce(
              (nearest, player) => {
                const distance = Math.sqrt(
                  Math.pow(player.location.x - killedEntity.location.x, 2) +
                    Math.pow(player.location.y - killedEntity.location.y, 2) +
                    Math.pow(player.location.z - killedEntity.location.z, 2)
                );
                return distance < nearest.distance ? { player, distance } : nearest;
              },
              { player: null, distance: Infinity }
            ).player;

            if (nearestPlayer) {
              if (goodMobs.includes(entityid) && affiliation(nearestPlayer) === "evil") {
                world
                  .getDimension("overworld")
                  .runCommand(`loot spawn ${locationString} loot "float/ad/infernal_shard"`);
              } else if (evilMobs.includes(entityid) && affiliation(nearestPlayer) === "good") {
                world
                  .getDimension("overworld")
                  .runCommand(`loot spawn ${locationString} loot "float/ad/crystalised_light"`);
              }
            }
          }
        }
      } catch (error) {}
    }
  }
});

// Event: Script event receive
system.afterEvents.scriptEventReceive.subscribe(handleScriptEvents);
const SETTINGS_EVENT_ID = "float_ad:showsettings";

// Handle script events
function handleScriptEvents(event) {
  if (event.id == SETTINGS_EVENT_ID) {
    showsettings(event.sourceEntity, event.message);
  }
}

// Leggings check
// Event: Player takes damage
world.afterEvents.entityHurt.subscribe((event) => {
  const player = event.hurtEntity;
  if (!player) {
    return;
  }
  if (player.id === undefined) {
    return;
  }
  try {
    const tags = player.getTags();
    if (!tags.includes("good") && !tags.includes("evil")) {
      return;
    }

    const now = Date.now();
    const lastUsed = leggingsCooldowns.get(player.id) || 0;

    if (now - lastUsed < 60000) {
      return; // 60 seconds cooldown
    }

    const affiliationType = affiliation(player);
    const currentTier =
      affiliationType === "good" ? Good.goodTier.get(player.id) || 1 : Evil.evilTier.get(player.id) || 1;

    const equipment = player.getComponent(EntityComponentTypes.Equippable);
    if (!equipment) return;

    const leggings = equipment.getEquipment(EquipmentSlot.Legs);
    if (!leggings) return;

    if (affiliationType === "good" && leggings.typeId.startsWith(`float_ad:good_`)) {
      const leggingsTier = parseInt(leggings.typeId.split("_")[2]);
      if (leggingsTier <= currentTier) {
        const duration = leggingsDurations.good[leggingsTier - 1] || 4000;
        goodLeggingsAbility(player, duration, currentTier);
        leggingsCooldowns.set(player.id, now);
      }
    } else if (affiliationType === "evil" && leggings.typeId.startsWith(`float_ad:evil_`)) {
      const leggingsTier = parseInt(leggings.typeId.split("_")[2]);
      if (leggingsTier <= currentTier) {
        const duration = leggingsDurations.evil[leggingsTier - 1] || 4000;
        evilLeggingsAbility(player, duration, currentTier);
        leggingsCooldowns.set(player.id, now);
      }
    }
  } catch (error) {}
});

var Players = undefined;
var Nearest = undefined;
var TempPlayer = undefined;
var Dist = 0.0;
var XDist = 0.0;
var ZDist = 0.0;
var i = 0;
system.afterEvents.scriptEventReceive.subscribe(async (event) => {
  const { id, message, initiator, sourceEntity, sourceType } = event;
  if (event.id == "float_ad:turnpage") {
    Players = world.getAllPlayers();
    Nearest = undefined;
    TempPlayer = undefined;
    Dist = Infinity;
    XDist = 0.0;
    ZDist = 0.0;
    i = 0;
    for (;;) {
      TempPlayer = Players[i];
      if (String(TempPlayer.name).valueOf() == String(message).valueOf()) {
        if (Nearest == undefined) {
          Nearest = TempPlayer;
          XDist *= XDist;
          ZDist = TempPlayer.location.z - sourceEntity.location.z;
          ZDist *= ZDist;
          Dist = XDist + ZDist;
        } else {
          XDist = TempPlayer.location.x - sourceEntity.location.x;
          XDist *= XDist;
          ZDist = TempPlayer.location.z - sourceEntity.location.z;
          ZDist *= ZDist;
          if (Dist > XDist + ZDist) {
            Dist = XDist + ZDist;
            Nearest = TempPlayer;
          }
        }
      }
      i++;
      if (i >= Players.length) {
        if (Nearest == undefined) {
        } else {
          let deltaX = Nearest.location.x - sourceEntity.location.x;
          let deltaZ = Nearest.location.z - sourceEntity.location.z;
          let targetAngle = Math.atan2(deltaZ, deltaX);
          let playerRotation = Nearest.getRotation().y * (Math.PI / 180);
          let angleDifference = targetAngle - playerRotation;
          angleDifference = ((angleDifference + Math.PI) % (2 * Math.PI)) - Math.PI / 2.0;
          let currentpage = sourceEntity.getProperty("float_ad:page");
          if (angleDifference > 0) {
            system.runTimeout(() => {
              world.getDimension("overworld").runCommand(`event entity @e[type=float_ad:book,c=1] float_ad:backflip`);
              world
                .getDimension("overworld")
                .runCommand(`event entity @e[type=float_ad:book_hub,c=1] float_ad:backflip`);
            }, 0);
          }
        }
        return;
      }
    }
  }
});
