import { system, world } from "@minecraft/server";
import { hostileMobs } from "../variables.js";

// Main function to activate the good dagger ability
export default function goodDaggerAbility(player, daggerTier) {
  const playerLocation = player.location;
  const playerDirection = player.getViewDirection();

  let particleEffect;
  let damageAmount;
  let attackCount;

  // Determine the ability parameters based on the dagger tier
  switch (daggerTier) {
    case 1:
      particleEffect = "float_ad:good_dagger_strike_1";
      damageAmount = 10;
      attackCount = 2;
      break;
    case 2:
      particleEffect = "float_ad:good_dagger_strike_2";
      damageAmount = 20;
      attackCount = 4;
      break;
    case 3:
      particleEffect = "float_ad:good_dagger_strike_3";
      damageAmount = 30;
      attackCount = 6;
      break;
    default:
      return;
  }

  // Play sound
  player.playSound("float_ad.dagger_ability_good");

  // Start the attack sequence with a delay
  system.runTimeout(() => {
    attackEntities(player, playerLocation, attackCount, damageAmount, particleEffect);
  }, 5); // 0.25-second delay
}

// Function to attack entities
function attackEntities(player, playerLocation, attackCount, damage, effect, attackedEntities = []) {
  if (attackCount <= 0) {
    return;
  }

  // Get entities within a certain distance
  const entities = player.dimension.getEntities({
    location: playerLocation,
    maxDistance: 16,
  });

  // Find the closest visible entity that hasn't been attacked yet
  let closestEntity = findClosestVisibleEntity(player, playerLocation, entities, attackedEntities);

  if (!closestEntity) {
    return;
  }

  // Teleport the player near the closest entity and attack it
  system.runTimeout(() => {
    player
      .runCommandAsync(
        `execute as "${player.name}" at "${player.name}" run tp "${player.name}" ${closestEntity.location.x} ${closestEntity.location.y} ${closestEntity.location.z}`
      )
      .then(() => {
        const direction = {
          x: player.location.x - closestEntity.location.x,
          y: player.location.y - closestEntity.location.y,
          z: player.location.z - closestEntity.location.z,
        };
        const distance = Math.sqrt(direction.x ** 2 + direction.y ** 2 + direction.z ** 2);
        const normalizedDirection =
          distance === 0
            ? { x: 1, y: 0, z: 0 }
            : {
                x: direction.x / distance,
                y: direction.y / distance,
                z: direction.z / distance,
              };
        const newLocation = {
          x: closestEntity.location.x + normalizedDirection.x,
          y: closestEntity.location.y + normalizedDirection.y,
          z: closestEntity.location.z + normalizedDirection.z,
        };

        const yaw = Math.atan2(-normalizedDirection.z, -normalizedDirection.x) * (180 / Math.PI) - 90;
        const pitch = Math.asin(-normalizedDirection.y) * (180 / Math.PI);

        if (!isNaN(newLocation.x) && !isNaN(newLocation.y) && !isNaN(newLocation.z)) {
          player
            .runCommandAsync(
              `execute as "${player.name}" at "${player.name}" run tp "${player.name}" ${newLocation.x} ${newLocation.y} ${newLocation.z} ${yaw} ${pitch}`
            )
            .then(() => {
              system.runTimeout(() => {
                closestEntity.applyDamage(damage, { cause: "starve" });
                player.runCommandAsync(
                  `particle ${effect} ${closestEntity.location.x} ${closestEntity.location.y} ${closestEntity.location.z}`
                );
                attackedEntities.push(closestEntity);
                attackEntities(player, player.location, attackCount - 1, damage, effect, attackedEntities);
              }, 2);
            });
        }
      })
      .catch(() => {
        // Handle teleport failure
      });
  }, 2);
}

// Function to find the closest visible entity that hasn't been attacked yet
function findClosestVisibleEntity(player, playerLocation, entities, attackedEntities) {
  let closestEntity = null;
  let minDistance = Infinity;

  for (const entity of entities) {
    if (!hostileMobs.includes(entity.typeId) || attackedEntities.includes(entity)) {
      continue;
    }

    const distance = Math.sqrt(
      (entity.location.x - playerLocation.x) ** 2 +
        (entity.location.y - playerLocation.y) ** 2 +
        (entity.location.z - playerLocation.z) ** 2
    );

    if (!isObstructed(player, playerLocation, entity.location) && distance < minDistance) {
      minDistance = distance;
      closestEntity = entity;
    }
  }

  return closestEntity;
}

// Function to check if there is an obstruction between two points
function isObstructed(player, start, end) {
  const direction = {
    x: end.x - start.x,
    y: end.y - start.y,
    z: end.z - start.z,
  };
  const distance = Math.sqrt(direction.x ** 2 + direction.y ** 2 + direction.z ** 2);

  const block = player.dimension.getBlockFromRay(start, direction, {
    maxDistance: distance,
    includePassableBlocks: false,
  });

  return block && block.location ? true : false;
}
