import {
  ItemStack, EntityEquippableComponent, EntityInventoryComponent,
  EntityProjectileComponent, GameMode, ItemDurabilityComponent,
  ItemEnchantableComponent, system, world
} from "@minecraft/server";


function getTridentItem(item) {
  const tridentItem = {
    itemID: item.typeId
  };
  tridentItem.nameTag = item.nameTag;
  const durComp = item.getComponent(ItemDurabilityComponent.componentId);
  if (durComp)
    tridentItem.durabilityDamage = durComp.damage;
  const enchComp = item.getComponent(ItemEnchantableComponent.componentId);
  const enchants = [];
  if (enchComp)
    for (const enchant of enchComp.getEnchantments())
      enchants.push({ id: `enchant.${enchant.type.id}`, lvl: enchant.level });
  if (enchants[0])
    tridentItem.enchantments = enchants;
  return tridentItem;
}
async function getItem(tridentItem, container, player) {
  const item = new ItemStack(tridentItem.itemID);
  const durComp = item.getComponent(ItemDurabilityComponent.componentId);
  if (durComp && tridentItem.durabilityDamage)
    durComp.damage = tridentItem.durabilityDamage > durComp.maxDurability ? durComp.maxDurability : tridentItem.durabilityDamage;
  item.nameTag = tridentItem.nameTag;


  const equippable = player.getComponent("minecraft:equippable")
  const mainHand = equippable.getEquipmentSlot("Mainhand").getItem()
  if (mainHand != undefined)
    container.addItem(mainHand)
  equippable.setEquipment("Mainhand", item)

  await sleep(1)
  if (tridentItem.enchantments)
    for (const enchant of tridentItem.enchantments)
      player.runCommand(`/enchant @s ${enchant.id.replace("enchant.", "")} ${enchant.lvl}`)
}

function canPickUp(entity) {
  return entity.getDynamicProperty("returning") || entity.isOnGround
}
function getOwner(ownerID) {
  return world.getEntity(ownerID);
}
function reduceDurability(tridentItem) {
  const unbreaking = tridentItem.enchantments?.find((f) => f.id == "unbreaking");
  if (!unbreaking)
    return true;
  const chance = 100 / (unbreaking.lvl + 1);
  const randomNum = Math.random() * 100;
  return randomNum >= (100 - chance);
}

const riptideSound = ["item.trident.riptide_1", "item.trident.riptide_2", "item.trident.riptide_3"]
world.afterEvents.itemReleaseUse.subscribe((data) => {
  const { source, useDuration } = data;
  if (!data.itemStack)
    return;
  const mainhand = source.getComponent(EntityEquippableComponent.componentId)?.getEquipmentSlot("Mainhand");
  if (!mainhand)
    return;
  const item = mainhand.getItem();
  if (item?.typeId != data.itemStack.typeId)
    return;

  if (!item.typeId.includes("4ks_wp:") || (!item.typeId.includes("_trident") && !item.typeId.includes("_javelin"))) return
  if (-useDuration + 19999980 < 13) return;


  const enchComp = item.getComponent(ItemEnchantableComponent.componentId);
  if (enchComp?.hasEnchantment("riptide")) {
    const level = enchComp.getEnchantment("riptide")?.level;
    if (level === undefined)
      return;
    if (source.isInWater || world.getDynamicProperty("4ks_wp:raining") || world.getDynamicProperty("4ks_wp:thunderstorm")) {

      const viewDir = source.getViewDirection();
      const verticalStrength = [
        viewDir.y * 1.6,
        viewDir.y * 2.3,
        viewDir.y * (2.4 + ((2.4 / 11) * level))]

      const yaw = source.getRotation().y * (Math.PI / 180);
      const horizontalStrength = [4.0, 5.75, 7];

      source.applyKnockback(
        -Math.sin(yaw),
        Math.cos(yaw),
        horizontalStrength[level - 1],
        verticalStrength[level-1]
      );

      const hitEntities = source.getEntitiesFromViewDirection({ maxDistance: 10 })
      for (const entity of hitEntities) {
        if (entity.id == source.id) continue
        entity.entity.applyDamage(6, { cause: "entityAttack", damagingEntity: source })
      }
      source.dimension.playSound(riptideSound[level - 1], source.location);
      return;
    }
    return;
  }
  const durComp = item.getComponent(ItemDurabilityComponent.componentId);
  if (durComp?.damage == durComp?.maxDurability)
    return;
  const projectileID = item.typeId + "_thrown";
  const headLoc = source.getHeadLocation();
  const viewDirection = source.getViewDirection();
  const projectile = source.dimension.spawnEntity(projectileID, { x: viewDirection.x + headLoc.x, y: viewDirection.y + headLoc.y, z: viewDirection.z + headLoc.z });
  projectile.teleport(headLoc);
  projectile.setDynamicProperty("item", JSON.stringify(getTridentItem(item)));
  if (source.getGameMode() != GameMode.creative)
    mainhand.setItem(new ItemStack("minecraft:air"));
  projectile.setDynamicProperty("ownerID", source.id);
  const projectileComp = projectile.getComponent(EntityProjectileComponent.componentId);
  if (enchComp?.getEnchantments()[0])
    projectile.setProperty('4ks_wp:enchanted', true);
  if (!projectileComp)
    return;
  projectileComp.owner = source;
  //const viewDir = source.getViewDirection();



  // projectile.clearVelocity();
  // projectile.applyImpulse(VOP.multiply(view, VEL));
  const velocity = {
    x: source.getViewDirection().x * 5,
    y: source.getViewDirection().y * 5,
    z: source.getViewDirection().z * 5,
  };
  projectileComp.shoot(velocity);

  source.dimension.playSound("item.trident.throw", source.location, { volume: 1, pitch: 1 });



  // projectile_pool.push({
  //   entity: projectile,
  //   location: projectile.location,
  //   rotation,
  //   view
  // });
});
world.afterEvents.projectileHitBlock.subscribe((data) => {
  const { projectile } = data;
  system.runTimeout(() => {
    if (!projectile || !projectile.isValid())
      return;

    projectile.setDynamicProperty("4ks_wp:projectile_hit", true)
    let itemData = projectile.getDynamicProperty("item");
    if (!itemData)
      return;
    itemData = JSON.parse(itemData);
    if (itemData.durabilityDamage === undefined)
      return;
    reduceDurability(itemData)
    itemData.durabilityDamage += 1;
    projectile.setDynamicProperty("item", JSON.stringify(itemData));
    projectile.clearVelocity()
    projectile.teleport(data.location)
    if (!itemData.enchantments)
      return;
    const loyalty = itemData.enchantments.find((f) => f.id == "enchant.loyalty");
    if (!loyalty)
      return;
    projectile.triggerEvent("4ks_wp:returning");
  }, 3);
});
world.afterEvents.projectileHitEntity.subscribe((data) => {
  const { projectile } = data;
  const victim = data.getEntityHit().entity;
  system.runTimeout(() => {
    if (!projectile || !projectile.isValid())
      return;

    if (projectile.typeId.includes("_trident"))
      projectile.setDynamicProperty("4ks_wp:projectile_hit", true)
    let itemData = projectile.getDynamicProperty("item");
    if (!itemData)
      return;
    itemData = JSON.parse(itemData);
    if (itemData.durabilityDamage === undefined)
      return;
    if (!reduceDurability(itemData))
      return;
    itemData.durabilityDamage += 1;
    projectile.setDynamicProperty("item", JSON.stringify(itemData));
    if (!itemData.enchantments)
      return;
    const channeling = itemData.enchantments.find((f) => f.id == "enchant.channeling");
    if (channeling && world.getDynamicProperty("4ks_wp:thunderstorm")) {
      victim.runCommand("/summon lightning_bolt ~~~")
    }

    const impaling = itemData.enchantments.find((f) => f.id == "enchant.impaling");
    if (impaling && victim.isInWater) {
      const damage = 2.5 * impaling.lvl
      const healthComponent = victim?.getComponent("minecraft:health");
      if (healthComponent) {
        healthComponent.setCurrentValue(healthComponent.currentValue - damage)
      }
    }
    const loyalty = itemData.enchantments.find((f) => f.id == "enchant.loyalty");
    if (!loyalty)
      return;
    projectile.triggerEvent("4ks_wp:returning");
  }, 3);
});


function sleep(tick) {
  return new Promise(resolve => {
    system.runTimeout(() => {
      resolve(tick)
    }, tick)
  })
}
system.afterEvents.scriptEventReceive.subscribe(async (data) => {
  if (data.id == "4ks_wp:player_pickup") {
    const tridentEntity = data.sourceEntity;
    if (!tridentEntity || !tridentEntity.isValid()) return

    const player = tridentEntity.dimension.getEntities({ location: tridentEntity.location, maxDistance: 2, type: "minecraft:player", closest: 1 })[0];
    if (!player) return
    const inv = player.getComponent(EntityInventoryComponent.componentId);
    if (!inv || !inv.container || inv.container.emptySlotsCount == 0)
      return;
    const container = inv.container;

    if (!tridentEntity || !tridentEntity.isValid() || !canPickUp(tridentEntity)) return

    const ownerID = tridentEntity.getDynamicProperty("ownerID");
    if (!ownerID || ownerID != player.id) return;

    const itemData = tridentEntity.getDynamicProperty("item");
    if (!itemData) return;

    const gameMode = player.getGameMode();
    if (gameMode != GameMode.creative && gameMode != GameMode.spectator) {
      const item = getItem(JSON.parse(itemData), container, player);
      //inv.container.addItem(item);
    }
    player.dimension.playSound("random.pop", tridentEntity.location, { pitch: 1 + Math.random(), volume: 0.5 });
    tridentEntity.triggerEvent("4ks_wp:despawn")
  }

  if (data.id != "4ks_wp:trident_return" && data.id != "4ks_wp:trident_tick")
    return;
  const tridentEntity = data.sourceEntity;
  if (!tridentEntity || !tridentEntity.isValid())
    return;

  if (data.id == "4ks_wp:trident_return") {
    if (!tridentEntity || !tridentEntity.isValid()) return
    let itemData = tridentEntity.getDynamicProperty("item");
    if (!itemData)
      return;

    itemData = JSON.parse(itemData);
    if (!itemData.enchantments)
      return;
    const loyalty = itemData.enchantments.find((f) => f.id == "enchant.loyalty");
    if (!loyalty)
      return;
    const ownerID = tridentEntity.getDynamicProperty("ownerID");
    if (!ownerID)
      return;
    const owner = getOwner(ownerID);
    if (!owner)
      return;
    if (!tridentEntity || !tridentEntity.isValid() || !owner || !owner.isValid())
      return;
    const loc = tridentEntity.location;
    let velocity = 1
    if (!loyalty)
      return;
    velocity *= 1 + (loyalty.lvl * 0.25);
    let tridentLoc = tridentEntity.location;

    const ownerLoc = owner.location;
    tridentEntity.teleport(loc, { facingLocation: { x: ownerLoc.x, y: ownerLoc.y + 1, z: ownerLoc.z } });
    const viewDir = tridentEntity.getViewDirection();
    tridentEntity.teleport({ x: loc.x + viewDir.x + (viewDir.x * velocity), y: loc.y + viewDir.y + (viewDir.y * velocity), z: loc.z + (viewDir.z * velocity) });

    if (!tridentEntity || !tridentEntity.isValid()) return
    if (tridentEntity.getDynamicProperty("returning"))
      return;
    tridentEntity.setDynamicProperty("returning", true);

    if (owner.typeId == "minecraft:player")
      owner.playSound("item.trident.return", { volume: 1, pitch: 1 });
  }
  else if (tridentEntity.location.y < -64) {
    tridentEntity.runCommand("scriptevent 4ks_wp:trident_return");
  }
  return;
});