
import { system, MolangVariableMap, Entity, ItemStack } from "@minecraft/server";
import { DYNAMIC_PROPERTY, ABILITY_DELAY_TICK, WEAPON_EFFECT_STATS, OTHER_DAMAGE, blacklistedEnemy } from "./data";
import { getRandomNumber, getRandomFloat, checkInventoryHaveItem } from "./utils/helpers";

function sleep(tick) {
  return new Promise(resolve => {
    system.runTimeout(() => {
      resolve(tick)
    }, tick)
  })
}
export async function useThrowingStar(player, itemID) {
  const velocity = {
    x: player.getViewDirection().x * 5,
    y: player.getViewDirection().y * 5,
    z: player.getViewDirection().z * 5,
  };
  const headLocation = player.getHeadLocation();
  const viewDirection = player.getViewDirection();
  
  let entityToSpawn = itemID.typeId
  if(itemID.amount == 1) entityToSpawn += "_dmg"
  const projectile = player.dimension.spawnEntity(entityToSpawn, {
    x: headLocation.x + viewDirection.x * 2,
    y: headLocation.y + viewDirection.y * 2,
    z: headLocation.z + viewDirection.z * 2
  });


  const projectileComp = projectile.getComponent('minecraft:projectile');

  projectileComp?.shoot(velocity)
  projectileComp.owner = player
  player.runCommand(`/clear @s ${itemID.typeId} 0 1`)
  player.runCommand("/playsound random.bow @a[r=8] ~~~")
}
export async function netheriteBowSpecialOnuse(player) {
  if (system.currentTick - player.getDynamicProperty("4ks_wp:use_tick") < 24) return
  const holdDuration = system.currentTick - player.getDynamicProperty("4ks_wp:use_tick")
  const item = player.getComponent("minecraft:equippable")?.getEquipment("Mainhand")
  const haveInfinity = item?.getComponent("minecraft:enchantable")?.hasEnchantment("infinity")
  if (holdDuration % 20 == 0 && !haveInfinity) {
    player.runCommand("/clear @s minecraft:arrow 0 1");
    
    const currentDurabilityDamage = player.getDynamicProperty("4ks_wp:durability_reduce") ?? 0
    player.setDynamicProperty("4ks_wp:durability_reduce", currentDurabilityDamage + 1)
  }
  if (!checkInventoryHaveItem(player, "minecraft:arrow", 1)) {
    player.setDynamicProperty("4ks_wp:netherite_bow_special_delay", false)
    return
  }
  
  if (player.getDynamicProperty("4ks_wp:netherite_bow_special_delay")) return
  player.setDynamicProperty("4ks_wp:netherite_bow_special_delay", true)
  const entity = player.getEntitiesFromViewDirection({ maxDistance: 32 })
  if (entity.length == 0) {
    const block = player.getBlockFromViewDirection({ maxDistance: 32 })
    if (!block) {
      player.setDynamicProperty("4ks_wp:netherite_bow_special_delay", false)
      return
    }
    const location = block.block.location

    player.runCommand(`/summon 4ks_wp:falling_netherite ${location.x} ${location.y + 12} ${location.z}`)
  } else {
    const location = entity[0].entity.location
    player.runCommand(`/summon 4ks_wp:falling_netherite ${location.x} ${location.y + 12} ${location.z}`)
  }

  await sleep(10)
  player.setDynamicProperty("4ks_wp:netherite_bow_special_delay", false)

}



export async function woodBowSpecialOnuse(player) {
  if (system.currentTick - player.getDynamicProperty("4ks_wp:use_tick") < 24) return
  const holdDuration = system.currentTick - player.getDynamicProperty("4ks_wp:use_tick")
  const item = player.getComponent("minecraft:equippable")?.getEquipment("Mainhand")
  const haveInfinity = item?.getComponent("minecraft:enchantable")?.hasEnchantment("infinity")
  if (holdDuration % 20 == 0 && !haveInfinity) {
    player.runCommand("/clear @s minecraft:arrow 0 1");
    
    const currentDurabilityDamage = player.getDynamicProperty("4ks_wp:durability_reduce") ?? 0
    player.setDynamicProperty("4ks_wp:durability_reduce", currentDurabilityDamage + 1)
  }
  if (!checkInventoryHaveItem(player, "minecraft:arrow", 1)) {
    player.setDynamicProperty("4ks_wp:wood_bow_special_delay", false)
    return
  }
  
  if (player.getDynamicProperty("4ks_wp:wood_bow_special_delay")) return
  player.setDynamicProperty("4ks_wp:wood_bow_special_delay", true)
  const velocity = {
    x: player.getViewDirection().x * 5,
    y: player.getViewDirection().y * 5,
    z: player.getViewDirection().z * 5,
  };
  const headLocation = player.getHeadLocation();
  const viewDirection = player.getViewDirection();
  const projectile = player.dimension.spawnEntity("4ks_wp:wood_bow_arrow", {
    x: headLocation.x + viewDirection.x * 2,
    y: headLocation.y + viewDirection.y * 2,
    z: headLocation.z + viewDirection.z * 2
  });

  player.runCommand(`/playsound random.bow @a[r=16] ~~~`)


  const projectileComp = projectile.getComponent('minecraft:projectile');

  projectileComp?.shoot(velocity)
  await sleep(2)
  player.setDynamicProperty("4ks_wp:wood_bow_special_delay", false)
}

export async function woodSwordSpecialOnuse(player) {
  player?.runCommand(`/playsound 4ks_wp.wood_use @a[r=16] ~~~ 0.7`)
  const velocity = {
    x: player.getViewDirection().x * 1,
    y: player.getViewDirection().y * 1,
    z: player.getViewDirection().z * 1,
  };
  const headLocation = player.getHeadLocation();
  const viewDirection = player.getViewDirection();
  const projectile = player.dimension.spawnEntity("4ks_wp:wooden_ball_cage", {
    x: headLocation.x + viewDirection.x * 5,
    y: headLocation.y + viewDirection.y * 5,
    z: headLocation.z + viewDirection.z * 5
  });


  const projectileComp = projectile.getComponent('minecraft:projectile');

  projectileComp?.shoot(velocity)
  await sleep(2)
  projectile.triggerEvent("4ks_wp:allow_check")
}

export async function stoneSwordSpecialOnuse(player) {
  player?.runCommand(`/playsound 4ks_wp.stone_use @a[r=16] ~~~ 0.7`)
  const velocity = {
    x: player.getViewDirection().x * 2,
    y: player.getViewDirection().y * 2,
    z: player.getViewDirection().z * 2,
  };
  const headLocation = player.getHeadLocation();
  const viewDirection = player.getViewDirection();
  const projectile = player.dimension.spawnEntity("4ks_wp:sword_rollout", {
    x: headLocation.x + viewDirection.x * 3,
    y: headLocation.y + viewDirection.y * 3,
    z: headLocation.z + viewDirection.z * 3
  });


  const projectileComp = projectile.getComponent('minecraft:projectile');

  projectileComp?.shoot(velocity)
}

export async function ironSwordSpecialOnuse(player) {
  player.runCommand(`/playsound 4ks_wp.iron_use @s ~~~ 0.6`)
  const velocity = {
    x: player.getViewDirection().x * 2,
    y: player.getViewDirection().y * 2,
    z: player.getViewDirection().z * 2,
  };
  const headLocation = player.getHeadLocation();
  const viewDirection = player.getViewDirection();
  const projectile = player.dimension.spawnEntity("4ks_wp:spinning_sword", {
    x: headLocation.x + viewDirection.x * 3,
    y: headLocation.y + viewDirection.y * 3,
    z: headLocation.z + viewDirection.z * 3
  });


  let movingDistance = 20
  while (movingDistance-- > 0 && !projectile?.getDynamicProperty('4ks_wp:stop_moving')) {
    // Check for solid blocks in front of the projectile
    const currentLocation = projectile.location;
    const blockInFront = projectile.dimension.getBlock({
      x: currentLocation.x + velocity.x * 1,
      y: currentLocation.y + velocity.y * 1,
      z: currentLocation.z + velocity.z * 1
    });

    // Stop if there's a solid block (not air, water, or lava)
    if (blockInFront &&
      blockInFront.typeId !== "minecraft:air" &&
      blockInFront.typeId !== "minecraft:water" &&
      blockInFront.typeId !== "minecraft:lava") {
      projectile?.clearVelocity();
      projectile?.setDynamicProperty('4ks_wp:stop_moving', true);
      break;
    }

    projectile?.clearVelocity();
    projectile?.applyImpulse(velocity);
    await sleep(1);
    if(!projectile.isValid() || !projectile) return
  }
  if (!projectile.getDynamicProperty('4ks_wp:stop_moving'))
    projectile?.triggerEvent("4ks_wp:despawn")

}

export async function spinningSwordStopMove(event) {
  const entity = event.sourceEntity
  if(entity.getDynamicProperty(`4ks_wp:spinning_sword_delay`)) return
  entity.setDynamicProperty(`4ks_wp:spinning_sword_delay`, true)
  entity?.setDynamicProperty('4ks_wp:stop_moving', true)
  entity?.clearVelocity()
  entity?.runCommand(`/playsound 4ks_wp.iron_ability_use @a[r=16] ~~~ 0.8`)

  await sleep(80)
  entity?.runCommand(`/stopsound @a[r=16] 4ks_wp.iron_ability_use`)
  entity?.triggerEvent("4ks_wp:despawn")
}

export async function goldSwordSpecialOnuse(player) {
  const rayEntity = player.getEntitiesFromViewDirection({ maxDistance: WEAPON_EFFECT_STATS.gold_sword_ray_distance })
  player.runCommand(`/playsound 4ks_wp.bedrock_use @s ~~~ 0.75`)
  if (rayEntity.length == 0) {
    const rayBlock = player.getBlockFromViewDirection({ maxDistance: WEAPON_EFFECT_STATS.gold_sword_ray_distance })
    if (!rayBlock) {
      const viewDirection = player.getViewDirection();
      player.applyKnockback(viewDirection.x, viewDirection.z, 8, 0.2);
      await sleep(2)
      player.runCommand("/summon 4ks_wp:gold_sword_explosion_1")
      await sleep(2)
      player.runCommand("/summon 4ks_wp:gold_sword_explosion_2")
      await sleep(2)
      player.runCommand("/summon 4ks_wp:gold_sword_explosion_3")
      return

    }

    const location = rayBlock.block.location
    player.runCommand(`/tp ${location.x} ${location.y + 1} ${location.z}`)
    player.runCommand("/summon 4ks_wp:gold_sword_explosion_1")
    await sleep(5)
    player.runCommand("/summon 4ks_wp:gold_sword_explosion_2")
    await sleep(5)
    player.runCommand("/summon 4ks_wp:gold_sword_explosion_3")
    return
  }

  const location = rayEntity[0].entity.location
  player.runCommand(`/tp ${location.x} ${location.y} ${location.z}`)
  player.runCommand("/summon 4ks_wp:gold_sword_explosion_1")
  await sleep(5)
  player.runCommand("/summon 4ks_wp:gold_sword_explosion_2")
  await sleep(5)
  player.runCommand("/summon 4ks_wp:gold_sword_explosion_3")
}

async function sapphireBeam(player) {
  if (player.getDynamicProperty(DYNAMIC_PROPERTY.sapphire_beam_delay)) return
  player.setDynamicProperty(DYNAMIC_PROPERTY.sapphire_beam_delay, true)
  for (const victim of player.getEntitiesFromViewDirection({ maxDistance: WEAPON_EFFECT_STATS.sapphire_beam_range, excludeTypes: blacklistedEnemy })) {
    if (victim.id == player.id || victim.typeId == "minecraft:item") continue
    victim.entity.applyDamage(WEAPON_EFFECT_STATS.sapphire_beam_damage, { cause: "entityAttack", damagingEntity: player })
  }
  await sleep(ABILITY_DELAY_TICK.sapphire_beam_delay)
  player.setDynamicProperty(DYNAMIC_PROPERTY.sapphire_beam_delay, false)
}

export async function sapphireSwordSpecialOnuse(player) {
  sapphireBeam(player)
  if (player.getDynamicProperty(DYNAMIC_PROPERTY.sapphire_beam_sound_delay)) return
  player.setDynamicProperty(DYNAMIC_PROPERTY.sapphire_beam_sound_delay, true)
  player.runCommand("/playsound 4ks_wp.beam_loop @a[r=8]")
  await sleep(30)
  player.setDynamicProperty(DYNAMIC_PROPERTY.sapphire_beam_sound_delay, false)

}

export async function halberdAdded(event) {
  const sender = event.sourceEntity
  if (sender.hasTag("4kswpint") || sender.hasTag("4kswpjavusing") || sender.hasTag("4kswphalberd")) return
  sender.runCommand("/event entity @e[type=4ks_wp:invisible_hitter,r=3] 4ks_wp:despawn")
  sender.addTag("4kswphalberd")
  const entity = sender.dimension.spawnEntity("4ks_wp:invisible_hitter", sender.location)
  entity.setDynamicProperty("4kswpplayerid", sender.name)
}

export async function halberdRemoved(event) {
  const sender = event.sourceEntity
  sender.removeTag("4kswphalberd")
  sender.runCommand("/event entity @e[type=4ks_wp:invisible_hitter, c=1,r=3] 4ks_wp:despawn")
}

export async function rangeAttack(event) {
  const sender = event.sourceEntity
  const player = sender.dimension.getEntities({ location: sender.location, maxDistance: 3, type: "minecraft:player" })[0]
  if (player == undefined) return
  for (const victim of player.getEntitiesFromViewDirection({ maxDistance: WEAPON_EFFECT_STATS.halberd_spear_range, excludeTypes: blacklistedEnemy })) {
    if (victim.entity == undefined) continue
    if (victim.entity?.id == player.id || victim.entity?.typeId === '4ks_wp:invisible_hitter' || victim.entity?.typeId === 'minecraft:item') continue
    const equippable = player.getComponent("minecraft:equippable")
    const mainHand = equippable.getEquipment("Mainhand")

    if (mainHand != undefined) {
      const identifier = mainHand.typeId.replace("minecraft", "").replace("4ks_wp:", "")
      const oreType = identifier.split("_")[0]
      let weaponType = identifier.split("_")[1]
      if (oreType == "flame") {
        victim.entity.setOnFire(3, true)
      } else if (oreType == "cryo") {
        victim.entity.runCommand("/effect @s slowness 5 2")
      }

      if (OTHER_DAMAGE[oreType] != undefined && OTHER_DAMAGE[oreType]["items"][weaponType] != undefined) {
        victim.entity.runCommand(`/damage @s 0 entity_attack entity \"${player.name}\"`)

        const durabilityComponent = mainHand.getComponent('minecraft:durability');
        if (!durabilityComponent) return
        if (durabilityComponent.damage >= durabilityComponent.maxDurability) {
          player.runCommand("/playsound random.break @s")
          player.runCommand("/replaceitem entity @s slot.weapon.mainhand 0 minecraft:air")
          return
        }

        const enchantable = mainHand.getComponent('minecraft:enchantable')
        let addDamage = 1
        if (enchantable != undefined) {
          for (const enchant of enchantable.getEnchantments()) {
            if (enchant.type.id != "unbreaking") continue
            let chance = getRandomNumber(1, 100)
            if (enchant.level == 1) {
              if (chance <= 50) addDamage = 0
            } else if (enchant.level == 2) {
              if (chance <= 66) addDamage = 0
            } else if (enchant.level == 3) {
              if (chance <= 75) addDamage = 0
            }
          }
        }

        durabilityComponent.damage += addDamage
        durabilityComponent.damage = Math.min(durabilityComponent.damage, durabilityComponent.maxDurability)
        const equippable = player.getComponent("minecraft:equippable")
        if (durabilityComponent.damage >= durabilityComponent.maxDurability) {
          player.runCommand("/playsound random.break @s")
          player.runCommand("/replaceitem entity @s slot.weapon.mainhand 0 minecraft:air")
        } else
          equippable.setEquipment("Mainhand", mainHand)
      }
    }

    break
  }
  sender.triggerEvent("4ks_wp:remove_hit")
}


function applyKnockback(entity, vector) {
  const { x, y, z } = vector;
  const previousVelocity = entity.getVelocity();
  const horizontalNorm = Math.sqrt(x * x + z * z);
  let directionX = 0;
  let directionZ = 0;
  if (horizontalNorm !== 0) {
    directionX = x / horizontalNorm;
    directionZ = z / horizontalNorm;
  }
  const horizontalStrength = horizontalNorm * 2.5;
  const verticalStrength = y + (previousVelocity.y * 0.9);
  entity.applyKnockback(directionX, directionZ, horizontalStrength, verticalStrength);
}

async function netheriteExplodeEntity(player) {
  const { x, z } = player.getViewDirection();
  const knockbackStrength = WEAPON_EFFECT_STATS.club_knockback_strength.horizontal
  const knockbackVerticalStrength = WEAPON_EFFECT_STATS.club_knockback_strength.vertical
  for (const victim of player.dimension.getEntities({ location: player.location, maxDistance: 4, excludeTypes: blacklistedEnemy })) {
    if (victim == undefined) continue
    if (victim.id == player.id || victim.typeId == "minecraft:item" || victim.typeId == "minecraft:xp_orb") continue
    victim.applyKnockback(x, z, knockbackStrength, knockbackVerticalStrength);
    victim.applyDamage(6, { cause: "entityAttack", damagingEntity: player });
  }
}

function applyKnockbackFromEntity(centerEntity, victim, strength) {
  // Get the positions of the player and victim
  let playerPosition = centerEntity?.location;  // assuming this is a Vector3
  let victimPosition = victim?.location;  // assuming this is a Vector3

  // Calculate the direction from the victim to the player (this is the vector from victim to player)
  let dx = playerPosition.x - victimPosition.x;
  let dy = playerPosition.y - victimPosition.y;
  let dz = playerPosition.z - victimPosition.z;

  // Normalize this vector (so the direction is consistent regardless of distance)
  let magnitude = Math.sqrt(dx * dx + dy * dy + dz * dz);
  dx /= magnitude;
  dy /= magnitude;
  dz /= magnitude;

  // Now calculate the knockback direction by inverting the vector (moving away from the player)
  dx = -dx;
  dy = -dy;
  dz = -dz;

  // Apply the knockback impulse (scaled by strength)
  victim?.clearVelocity();
  victim?.applyImpulse({
    x: dx * strength,
    y: dy * strength,
    z: dz * strength
  });
}

export async function tornadoKnockback(event) {
  const entity = event.sourceEntity

  const entities = entity.dimension.getEntities({ location: entity.location, maxDistance: 4, families: ["mob"] })
  for (const ent of entities) {
    applyKnockbackFromEntity(entity, ent, 3)
  }
}


export async function bedrockSwordSpecialOnuse(player) {
  const hitBlock = player.getBlockFromViewDirection({ maxDistance: 192 })
  if (!hitBlock) {
    //player.runCommand("/execute rotated ~ 0 run summon 4ks_wp:bedrock_tornado ^^^8")
    return
  }

  player.runCommand(`/playsound 4ks_wp.bedrock_use @s ~~~ 0.75`)

  const blockLocation = hitBlock.block.location
  const teleportCoordinate = { x: blockLocation.x + hitBlock.faceLocation.x, y: blockLocation.y + hitBlock.faceLocation.y, z: blockLocation.z + hitBlock.faceLocation.z }
  if (hitBlock.faceLocation.z === 0) {
    teleportCoordinate.z -= 1;
  }
  if (hitBlock.faceLocation.x === 0) {
    teleportCoordinate.x -= 1;
  }
  player.runCommand(`/playsound 4ks_wp.tornado_loop @a[r=16] ${teleportCoordinate.x} ${teleportCoordinate.y} ${teleportCoordinate.z}`),
    player.runCommand(`/summon 4ks_wp:bedrock_tornado ${teleportCoordinate.x} ${teleportCoordinate.y} ${teleportCoordinate.z}`)
}

export async function obsidianSwordSpecialOnuse(player) {
  if (!player.getDynamicProperty(DYNAMIC_PROPERTY.obsidian_sword_spawned)) {
    const portalEntity = player.dimension.spawnEntity("4ks_wp:nether_portal", player.location)
    portalEntity.addTag(`4ks_wp_${player.id}`)
    player.setDynamicProperty(DYNAMIC_PROPERTY.obsidian_sword_spawned, true)
  }

  const hitBlock = player.getBlockFromViewDirection({ maxDistance: 8 })
  if (!hitBlock) {
    player.runCommand(`/execute if block ^^1^8 air run tp @e[type=4ks_wp:nether_portal,tag=4ks_wp_${player.id}] ^^1^8 facing @s true`)
    return
  }

  const blockCoordinate = hitBlock.block.location
  const teleportCoordinate = { x: blockCoordinate.x + hitBlock.faceLocation.x, y: blockCoordinate.y + hitBlock.faceLocation.y, z: blockCoordinate.z + hitBlock.faceLocation.z }
  if (hitBlock.faceLocation.z === 0) {
    teleportCoordinate.z -= 1;
  }
  if (hitBlock.faceLocation.x === 0) {
    teleportCoordinate.x -= 1;
  }
  player.runCommand(`tp @e[type=4ks_wp:nether_portal,tag=4ks_wp_${player.id}] ${teleportCoordinate.x} ${teleportCoordinate.y} ${teleportCoordinate.z} facing @s`)
}

export async function netherPortalTeleport(event) {
  const source = event.sourceEntity
  source.runCommand(`/playsound mob.shulker.teleport @a[r=16] ~~~`)
  source.setOnFire(WEAPON_EFFECT_STATS.nether_portal_fire_duration, true)
  const randomX = Math.floor(Math.random() * (WEAPON_EFFECT_STATS.nether_portal_xz_distance - (-WEAPON_EFFECT_STATS.nether_portal_xz_distance) + 1)) + (-WEAPON_EFFECT_STATS.nether_portal_xz_distance);
  const randomY = Math.floor(Math.random() * (WEAPON_EFFECT_STATS.nether_portal_xz_distance - (-WEAPON_EFFECT_STATS.nether_portal_xz_distance) + 1)) + (-WEAPON_EFFECT_STATS.nether_portal_xz_distance);
  source.runCommand(`/tp ~${randomX} ~20 ~${randomY}`)

}
export async function netheriteSwordSpecialOnuse(player) {
  const playerPosition = player.getViewDirection();
  playerPosition.x *= WEAPON_EFFECT_STATS.netherite_sword_leap_strength.horizontal
  playerPosition.y = WEAPON_EFFECT_STATS.netherite_sword_leap_strength.vertical
  playerPosition.z *= WEAPON_EFFECT_STATS.netherite_sword_leap_strength.horizontal
  player.runCommand(`/particle 4ks_wp:netherite_sword ^-0.35^1.5^4.3`)

  for (let i = 0; i < WEAPON_EFFECT_STATS.netherite_sword_leap_and_explosion_count; i++) {
    netheriteExplodeEntity(player)
    player.runCommand(`/particle 4ks_wp:netherite_explode_1`)
    player.runCommand(`/particle 4ks_wp:netherite_explode_2`)
    player.runCommand("/playsound 4ks_wp.netherite_onuse @a[r=8] ~~~")
    player.runCommand("/playsound random.explode @a[r=8]")
    applyKnockback(player, playerPosition)
    await sleep(WEAPON_EFFECT_STATS.netherite_sword_delay_per_leap_and_explosion)
  }
}

export async function sculkSwordSpecialOnuse(player) {
  const hitBlock = player.getBlockFromViewDirection({ maxDistance: 192 })
  if (!hitBlock) {
    return
  }
  player?.runCommand(`/playsound 4ks_wp.sculk_use @a[r=16] ~~~ 0.65`)

  const blockLocation = hitBlock.block.location
  const teleportCoordinate = { x: blockLocation.x + hitBlock.faceLocation.x, y: blockLocation.y + hitBlock.faceLocation.y, z: blockLocation.z + hitBlock.faceLocation.z }
  if (hitBlock.faceLocation.z === 0) {
    teleportCoordinate.z -= 1;
  }
  if (hitBlock.faceLocation.x === 0) {
    teleportCoordinate.x -= 1;
  }
  player.runCommand(`/summon 4ks_wp:spinning_warden ${teleportCoordinate.x} ${teleportCoordinate.y} ${teleportCoordinate.z}`)
}

export async function emeraldSwordSpecialOnhit(player, victim) {
  await sleep(1)
  const health = victim.getComponent("minecraft:health")

  if (health.currentValue <= 0) return
  victim.applyImpulse({ x: 0, y: WEAPON_EFFECT_STATS.emerald_sword_hit_levitation_strength, z: 0 });
  victim.runCommand("/particle 4ks_wp:emerald_mob_hit ~~0.8~")
}

export async function dragonSwordSpecialOnuse(player) {
  const projectileEntity = player.dimension.spawnEntity("4ks_wp:dragon_sword_projectile", {
    x: player.getHeadLocation().x + player.getViewDirection().x * 3.0,
    y: player.getHeadLocation().y + player.getViewDirection().y * 3.0,
    z: player.getHeadLocation().z + player.getViewDirection().z * 3.0
  });
  player.runCommand(`/playsound note.enderdragon @a[r=16]`)
}

export async function uraniumSwordSpecialOnuse(player) {
  player.runCommand("/clear @s 4ks_wp:uranium_ball 0 1")

  const velocity = {
    x: player.getViewDirection().x * 2,
    y: player.getViewDirection().y * 2,
    z: player.getViewDirection().z * 2,
  };
  const headLocation = player.getHeadLocation();
  const viewDirection = player.getViewDirection();
  const projectile = player.dimension.spawnEntity("4ks_wp:uranium_projectile", {
    x: headLocation.x + viewDirection.x * 2,
    y: headLocation.y + viewDirection.y * 2,
    z: headLocation.z + viewDirection.z * 2
  });


  const projectileComp = projectile.getComponent('minecraft:projectile');

  projectileComp?.shoot(velocity)
  projectileComp.owner = player
  player.runCommand("/playsound random.bow @a[r=8] ~~~")
}

export async function flameSwordSpecialOnuse(player) {
  player.runCommand("/playsound 4ks_wp.flame_onuse @a[r=8] ~~~")
  const molangMap = new MolangVariableMap()
  molangMap.setVector3("variable.data", { x: WEAPON_EFFECT_STATS.flame_sword_blast_radius, y: 0, z: 0 })
  player.dimension.spawnParticle("4ks_wp:flame_area", player.location, molangMap);
  player.runCommand(`/particle 4ks_wp:flame_sword ^-0.35^1.1^0.8`)
  player.runCommand(`/execute positioned as @e[r=${WEAPON_EFFECT_STATS.flame_sword_blast_radius},family=mob, type=!armor_stand] run summon 4ks_wp:burn_projectile ~~1~`)
  await sleep(1)
  for (const entity of player.dimension.getEntities({ location: player.location, maxDistance: WEAPON_EFFECT_STATS.flame_sword_blast_radius, excludeTypes: blacklistedEnemy })) {
    if (entity == undefined) continue
    if (entity.id == player.id || entity.typeId == "minecraft:item") continue
    entity.applyImpulse({ x: WEAPON_EFFECT_STATS.flame_sword_knockback_strength.horizontal, y: WEAPON_EFFECT_STATS.flame_sword_knockback_strength.vertical, z: WEAPON_EFFECT_STATS.flame_sword_knockback_strength.horizontal });
  }
  player.runCommand(`/damage @e[family=mob, type=!armor_stand, r=${WEAPON_EFFECT_STATS.flame_sword_blast_radius},rm=0.1] ${WEAPON_EFFECT_STATS.flame_sword_blast_damage} entity_attack entity @s`)



}

export async function emeraldSwordSpecialOnuse(player) {
  player.runCommand("/playsound 4ks_wp.emerald_onuse @a[r=8] ~~~")
  const molangMap = new MolangVariableMap()
  molangMap.setVector3("variable.data", { x: WEAPON_EFFECT_STATS.emerald_sword_ability_radius, y: 0, z: 0 })
  player.dimension.spawnParticle("4ks_wp:emerald_area", player.location, molangMap);
  player.runCommand(`/particle 4ks_wp:emerald_sword ^-0.35^1.1^0.8`)
  for (const entity of player.dimension.getEntities({ location: player.location, maxDistance: WEAPON_EFFECT_STATS.emerald_sword_ability_radius, excludeTypes: blacklistedEnemy })) {
    if (entity == undefined) continue
    if (entity.id == player.id || entity.typeId == "minecraft:item") continue
    entity.runCommand("/particle 4ks_wp:emerald_mob_hit ~~0.8~")
    entity.applyImpulse({ x: 0, y: WEAPON_EFFECT_STATS.emerald_sword_ability_levitation_strength, z: 0 });
  }
}

export async function cryoSwordSpecialOnuse(player) {
  player.runCommand(`/particle 4ks_wp:cryo_sword ^-0.35^1.1^0.8`)
  player.runCommand("/playsound 4ks_wp.cryo_onuse @a[r=8] ~~~")
  const molangMap = new MolangVariableMap()
  molangMap.setVector3("variable.data", { x: WEAPON_EFFECT_STATS.cryo_sword_radius, y: 0, z: 0 })
  player.dimension.spawnParticle("4ks_wp:ice_aoe_2", player.location, molangMap);


  player.runCommand(`/damage @e[family=mob, type=!armor_stand, r=${WEAPON_EFFECT_STATS.cryo_sword_radius},rm=0.1] ${WEAPON_EFFECT_STATS.cryo_sword_damage} entity_attack entity @s`)
  player.runCommand(`/effect @e[family=mob, type=!armor_stand, r=${WEAPON_EFFECT_STATS.cryo_sword_radius},rm=0.1] slowness ${WEAPON_EFFECT_STATS.cryo_sword_freeze_duration} 255 ${WEAPON_EFFECT_STATS.cryo_sword_hide_freeze_effect}`)

  await sleep(10)
  player.runCommand(`/execute as @e[family=mob, type=!armor_stand, r=${WEAPON_EFFECT_STATS.cryo_sword_radius},rm=0.1] positioned as @s run particle 4ks_wp:ice_on_mobs ~~0.8~`)
}

export async function dragonLingeringDamage(event) {
  const entity = event.sourceEntity

  entity.runCommand(`/damage @e[family=mob, type=!armor_stand, r=${WEAPON_EFFECT_STATS.dragon_sword_lingering_radius}] ${WEAPON_EFFECT_STATS.dragon_sword_lingering_damage_per_sec} entity_attack entity @p`)
}

export async function divineBeamDamage(event) {
  const entity = event.sourceEntity

  entity.runCommand(`/damage @e[family=mob, type=!armor_stand, r=4] ${WEAPON_EFFECT_STATS.divine_sword_beam_damage_per_tick} entity_attack entity @p`)
}

export async function amethystSwordSpecialOnuse(player) {
  if (player.getDynamicProperty(DYNAMIC_PROPERTY.amethyst_cooldown))
    return
  player.setDynamicProperty(DYNAMIC_PROPERTY.amethyst_cooldown, true)
  player.runCommand("/summon 4ks_wp:amethyst_seeker ^^1.0^4.0 ")
  player.runCommand("/summon 4ks_wp:amethyst_seeker ^-1.0^1.5^4.0 ")
  player.runCommand("/summon 4ks_wp:amethyst_seeker ^1.0^0.5^4.0 ")
  player.runCommand("/playsound 4ks_wp.amethyst_onuse @a[r=8] ~~~")
  await sleep(ABILITY_DELAY_TICK.amethyst_cooldown)
  player.setDynamicProperty(DYNAMIC_PROPERTY.amethyst_cooldown, false)
}

export async function divineSwordSpecialOnuse(player) {
  player.runCommand("/playsound 4ks_wp.divine_onuse @a[r=8] ~~~")
  player.runCommand(`/particle 4ks_wp:divine_sword ^-0.35^1.1^0.8`)
  let raycast = player.getEntitiesFromViewDirection({ maxDistance: WEAPON_EFFECT_STATS.divine_sword_beam_pointing_range, excludeTypes: blacklistedEnemy })
  let location;
  if (raycast.length == 0) {
    raycast = player.getBlockFromViewDirection({ maxDistance: WEAPON_EFFECT_STATS.divine_sword_beam_pointing_range * 2 })
    if (raycast == undefined) return
    location = raycast.block.location
  } else {
    location = raycast[0].entity.location
  }
  player.runCommand(`/summon 4ks_wp:divine_beam ${location.x} ${location.y} ${location.z}`)
  player.runCommand("/playsound 4ks_wp.divine_explode @a[r=64] ~~~")
}



export async function platinumSwordSpecialOnuse(player) {
  if (player.getDynamicProperty(DYNAMIC_PROPERTY.platinum_sword_cd_per_shoot))
    return
  player.setDynamicProperty(DYNAMIC_PROPERTY.platinum_sword_cd_per_shoot, true)
  const projectileEntity = player.dimension.spawnEntity("4ks_wp:platinum_projectile", {
    x: player.getHeadLocation().x + player.getViewDirection().x * 3.0,
    y: player.getHeadLocation().y + player.getViewDirection().y * 3.0,
    z: player.getHeadLocation().z + player.getViewDirection().z * 3.0
  });
  player.runCommand("/playsound 4ks_wp.platinum_onuse @a[r=8] ~~~")
  await sleep(ABILITY_DELAY_TICK.platinum_sword_cd_per_shoot)
  player.setDynamicProperty(DYNAMIC_PROPERTY.platinum_sword_cd_per_shoot, false)
}


export async function diamondSwordSpecialOnuse(player) {

  if (player.getDynamicProperty(DYNAMIC_PROPERTY.diamond_sword_cd))
    return
  player.setDynamicProperty(DYNAMIC_PROPERTY.diamond_sword_cd, true)
  player.runCommand("/playsound 4ks_wp.divine_onuse @a[r=8] ~~~")
  for (let i = 0; i < WEAPON_EFFECT_STATS.diamond_sword_projectile_count; i++) {
    const projectileEntity = player.dimension.spawnEntity("4ks_wp:diamond_projectile", {
      x: player.getHeadLocation().x + player.getViewDirection().x * getRandomFloat(1.5, 4),
      y: player.getHeadLocation().y + player.getViewDirection().y * getRandomFloat(1.5, 4),
      z: player.getHeadLocation().z + player.getViewDirection().z * getRandomFloat(1.5, 4),
    });
  }

  await sleep(ABILITY_DELAY_TICK.diamond_sword_cd)
  player.setDynamicProperty(DYNAMIC_PROPERTY.diamond_sword_cd, false)
}

export async function rubySwordSpecialOnuse(player) {
  if (player.getDynamicProperty(DYNAMIC_PROPERTY.ruby_sword_cd_per_shoot))
    return
  player.setDynamicProperty(DYNAMIC_PROPERTY.ruby_sword_cd_per_shoot, true)
  for (let i = 0; i < 5; i++) {
    const projectileEntity = player.dimension.spawnEntity("4ks_wp:ruby_projectile", {
      x: player.getHeadLocation().x + player.getViewDirection().x * 3.0,
      y: player.getHeadLocation().y + player.getViewDirection().y * 3.0,
      z: player.getHeadLocation().z + player.getViewDirection().z * 3.0
    });
  }
  player.runCommand("/playsound 4ks_wp.ruby_onuse @a[r=8] ~~~ 0.5")
  await sleep(ABILITY_DELAY_TICK.ruby_sword_cd_per_shoot)
  player.setDynamicProperty(DYNAMIC_PROPERTY.ruby_sword_cd_per_shoot, false)
}

export async function lapisSwordSpecialOnuse(player) {
  if (player.getDynamicProperty(DYNAMIC_PROPERTY.lapis_sword_cd_per_shoot))
    return
  player.runCommand("/playsound 4ks_wp.lapis_onuse @a[r=8] ~~~")
  player.setDynamicProperty(DYNAMIC_PROPERTY.lapis_sword_cd_per_shoot, true)
  player.runCommand(`/particle 4ks_wp:lapis_sword ^-0.35^1.1^0.8`)
  const projectileEntity = player.dimension.spawnEntity("4ks_wp:lapis_wave", {
    x: player.getHeadLocation().x + player.getViewDirection().x * 3.0,
    y: player.getHeadLocation().y + player.getViewDirection().y * 3.0,
    z: player.getHeadLocation().z + player.getViewDirection().z * 3.0
  });
  await sleep(ABILITY_DELAY_TICK.lapis_sword_cd_per_shoot)
  player.setDynamicProperty(DYNAMIC_PROPERTY.lapis_sword_cd_per_shoot, false)
}


export async function demonicSwordExplosion(entity) {
  for (let i = 0; i < WEAPON_EFFECT_STATS.demonic_sword_levitation_length; i++) {
    if (entity == undefined || !entity.isValid()) return
    entity.runCommand(`/damage @s ${WEAPON_EFFECT_STATS.demonic_sword_explosion_damage} entity_attack entity @p`)
    if (entity == undefined || !entity.isValid()) return
    entity.runCommand("/playsound 4ks_wp.demon_explode @a[r=16]")
    entity.runCommand("/particle 4ks_wp:demon_explosion ~~1~")
    await sleep(WEAPON_EFFECT_STATS.demonic_sword_explosion_interval)
    if (entity == undefined || !entity.isValid()) return
  }
}

export async function demonicSwordSpecialOnuse(player) {

  let entities = player.getEntitiesFromViewDirection({ maxDistance: WEAPON_EFFECT_STATS.demonic_sword_invisible_entity_range, excludeTypes: blacklistedEnemy })
  if (entities.length == 0) {
    const block = player.getBlockFromViewDirection({ maxDistance: WEAPON_EFFECT_STATS.demonic_sword_invisible_entity_range * 2 })?.block
    if (block == undefined) return
    player.runCommand(`/particle 4ks_wp:demon_explode_hit ${block.location.x} ${block.location.y + 1} ${block.location.z}`)
    entities = player.dimension.getEntities({ maxDistance: WEAPON_EFFECT_STATS.demonic_sword_radius, location: block.location, excludeTypes: blacklistedEnemy })
  } else {
    const entity = entities[0]?.entity
    entity?.runCommand(`/particle 4ks_wp:demon_explode_hit ${entity?.location.x} ${entity?.location.y + 1} ${entity?.location.z}`)
    entities = player.dimension.getEntities({ maxDistance: WEAPON_EFFECT_STATS.demonic_sword_radius, location: entity.location, excludeTypes: blacklistedEnemy })
  }

  if (entities.length == 0) return

  player.runCommand(`/particle 4ks_wp:demonic_sword ^-0.35^1.1^0.8`)
  player.runCommand("/playsound 4ks_wp.demon_onuse @a[r=16]")
  for (let i = 0; i < Math.min(WEAPON_EFFECT_STATS.demonic_sword_invisible_beam_entity_count, entities.length); i++) {
    let entity = entities[i]
    if (!(entity instanceof Entity)) entity = entities[i].entity
    if (entity == undefined) continue;
    if (entity.id == player.id || entity.typeId == "minecraft:item") continue
    entity.runCommand(`/effect @s levitation ${WEAPON_EFFECT_STATS.demonic_sword_levitation_length} ${WEAPON_EFFECT_STATS.demonic_sword_levitation_level} true`)
    entity.runCommand("/particle 4ks_wp:demon_mob_affected ~~~")
    entity.runCommand("/particle 4ks_wp:demon_floaty ~~~")
    demonicSwordExplosion(entity)
  }

}