import { world, system } from "@minecraft/server";

const TRACTOR_DURATION_TICKS = 60;
const UFO_FAMILY = "pb_plane_ufo";

const ALLOWED_ENTITY_TYPES = [
  "minecraft:cow",
  "minecraft:pig",
  "minecraft:chicken",
  "minecraft:zombie",
  "minecraft:villager",
  // Add more as needed
];

// Tractor beam event - triggered when interacting with the UFO
system.afterEvents.scriptEventReceive.subscribe((eventData) => {
  const { id, sourceEntity } = eventData;
  if (id !== "pb_plane:tractor_trigger") return;

  if (!sourceEntity || !sourceEntity.dimension) return;

  const ufo = sourceEntity;
  const isActive = ufo.getProperty("pb_plane:tractor_active") === true;
  const isCarrying = ufo.getProperty("pb_plane:tractor_carrying") === true;

  // If carrying something: drop it and stop the beam
  if (isCarrying) {
    releaseCarriedEntity(ufo);
    ufo.setProperty("pb_plane:tractor_active", false);
    ufo.setProperty("pb_plane:tractor_carrying", false);
    return;
  }

  // If tractor beam already active but no entity picked up: do nothing (already scanning)
  if (isActive) {
    return;
  }

  // Otherwise, activate tractor beam and scan for 3 seconds
  ufo.setProperty("pb_plane:tractor_active", true);
  ufo.playAnimation("animation.pb_plane.ufo_global.tractor_beam", {
    blendOutTime: 0.5,
    stopExpression: "query.any_animation_finished",
  });

  // Timeout: deactivate if nothing was picked up
  system.runTimeout(() => {
    const stillActive = ufo.getProperty("pb_plane:tractor_active") === true;
    const stillCarrying = ufo.getProperty("pb_plane:tractor_carrying") === true;

    if (stillActive && !stillCarrying) {
      ufo.setProperty("pb_plane:tractor_active", false);
    }
  }, TRACTOR_DURATION_TICKS);
});

system.runInterval(() => {
  const dimensions = ["overworld", "nether", "the_end"];
  const ufos = [];

  for (const dimName of dimensions) {
    const dim = world.getDimension(dimName);
    ufos.push(...dim.getEntities({ families: [UFO_FAMILY] }));
  }

  for (const ufo of ufos) {
    let tractorActive = ufo.getProperty("pb_plane:tractor_active") === true;
    let isCarrying = ufo.getProperty("pb_plane:tractor_carrying") === true;

    // 🧍‍♂️ If the UFO has no rider and is carrying something, cancel everything
    const hasRider =
      ufo.getComponent("minecraft:rideable").getRiders().length > 0;

    if (!hasRider && isCarrying) {
      //console.warn(`UFO ${ufo.id} has no rider — releasing carried entity.`);
      releaseCarriedEntity(ufo);
      ufo.setProperty("pb_plane:tractor_active", false);
      ufo.setProperty("pb_plane:tractor_carrying", false);
      continue;
    }

    // 🚜 Try to pick something up
    if (tractorActive && !isCarrying) {
      const target = findEntityBelow(ufo);
      if (target) {
        carryEntity(ufo, target);
        ufo.setProperty("pb_plane:tractor_carrying", true);
        isCarrying = true;
      }
    }

    // 🛰 Move carried entity
    if (isCarrying) {
      const carried = getCarriedEntity(ufo);

      if (!carried || !carried.isValid() || tooFarFromUfo(ufo, carried)) {
        releaseCarriedEntity(ufo);
        ufo.setProperty("pb_plane:tractor_active", false);
        ufo.setProperty("pb_plane:tractor_carrying", false);
        continue;
      }

      const ufoLoc = ufo.location;
      const hoverHeight = 2.5;
      const baseY = carried.location.y;
      const targetY = ufoLoc.y - hoverHeight;

      let liftProgress = carried.getDynamicProperty("lift_progress") ?? 0;
      if (typeof liftProgress !== "number") liftProgress = 0;

      const LIFT_SPEED = 0.001;
      liftProgress = Math.min(liftProgress + LIFT_SPEED, 1);
      carried.setDynamicProperty("lift_progress", liftProgress);

      const smoothY = baseY + (targetY - baseY) * liftProgress;

      const belowBlock = ufo.dimension.getBlock({
        x: Math.floor(ufoLoc.x),
        y: Math.floor(smoothY - 0.9),
        z: Math.floor(ufoLoc.z),
      });

      const isAir = belowBlock && belowBlock.typeId === "minecraft:air";
      const safeY = isAir ? smoothY : ufoLoc.y;

      carried.teleport(
        {
          x: ufoLoc.x,
          y: safeY,
          z: ufoLoc.z,
        },
        {
          facingLocation: ufoLoc,
          keepVelocity: false,
        }
      );

      ufo.setProperty("pb_plane:tractor_carrying", true);
    } else {
      ufo.setProperty("pb_plane:tractor_carrying", false);
    }

    if (!tractorActive) {
      ufo.setProperty("pb_plane:tractor_active", false);
    }
  }
});

function findEntityBelow(ufo) {
  const dim = ufo.dimension;
  const origin = ufo.location;

  for (let yOffset = 1; yOffset <= 10; yOffset++) {
    const checkPos = {
      x: origin.x,
      y: origin.y - yOffset,
      z: origin.z,
    };

    const candidates = dim.getEntities({
      location: checkPos,
      maxDistance: 1.25, // Within a ~1 block radius
      excludeFamilies: [UFO_FAMILY],
      excludeTags: ["pb_carried_by_ufo"],
    });

    for (const entity of candidates) {
      if (ALLOWED_ENTITY_TYPES.includes(entity.typeId)) {
        return entity;
      }
    }
  }

  return undefined;
}

function carryEntity(ufo, target) {
  target.addTag("pb_carried_by_ufo");
  target.setDynamicProperty("carried_by", ufo.id);
  target.setDynamicProperty("lift_progress", 0); // track lift from 0 to 1

  if (target.setVelocity) {
    target.setVelocity({ x: 0, y: 0, z: 0 });
  }

  ufo.playAnimation("animation.pb_plane.ufo_global.tractor_beam", {
    blendOutTime: 0.5,
    stopExpression: "query.any_animation_finished",
  });

  //(`Entity ${target.typeId} now carried by UFO ${ufo.id}`);
}

function getCarriedEntity(ufo) {
  const dim = ufo.dimension;
  const nearby = dim.getEntities({
    location: ufo.location,
    maxDistance: 8,
    tags: ["pb_carried_by_ufo"],
  });

  return nearby.find((e) => e.getDynamicProperty("carried_by") === ufo.id);
}

function releaseCarriedEntity(ufo) {
  ufo.setProperty("pb_plane:tractor_carrying", false);
  ufo.setProperty("pb_plane:tractor_active", false);
  const carried = getCarriedEntity(ufo);
  if (!carried) return;

  carried.removeTag("pb_carried_by_ufo");
  carried.setDynamicProperty("carried_by", undefined);

  // Gently drop
  carried.applyImpulse({ x: 0, y: -0.2, z: 0 });

  //console.warn(`Entity released from UFO ${ufo.id}`);
}

function tooFarFromUfo(ufo, entity) {
  const maxDistance = 12; // fail-safe range
  const dx = ufo.location.x - entity.location.x;
  const dy = ufo.location.y - entity.location.y;
  const dz = ufo.location.z - entity.location.z;
  const distSquared = dx * dx + dy * dy + dz * dz;
  return distSquared > maxDistance * maxDistance;
}
