import { ItemStack, system, world } from '@minecraft/server';
class Vec3 {
  constructor(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;
  }
  static add(a, b) {
    return new this(a.x + b.x, a.y + b.y, a.z + b.z);
  }
  static yRotated(vec3, rot) {
    rot = rot * (Math.PI/180);
    const cos = Math.cos(rot);
    const sin = Math.sin(rot);
    return new this(vec3.x * cos - vec3.z * sin, vec3.y, vec3.x * sin + vec3.z * cos);
  }
}
class bearFoodParticles {
  'sf_nba:bear_eating_honeycomb' = 1;
  'sf_nba:bear_eating_sweet_berries' = 2;
  'sf_nba:bear_eating_salmon' = 3;
  'sf_nba:bear_eating_cooked_salmon' = 4;
  'sf_nba:bear_eating_venison' = 5;
  static names() {
    return Object.getOwnPropertyNames(new this());
  }
  static getByValue(value) {
    return this.names().find(particle => new this()[particle] === value);
  }
}
function eatingEffects(bear, eatCounter) {
  if (eatCounter % 5 == 0 || eatCounter == 0) {
    const snoutVec = Vec3.add(Vec3.yRotated(new Vec3(0.07, 0.65, 1.21), bear.getRotation().y), bear.location);
    bear.dimension.spawnParticle(bearFoodParticles.getByValue(bear.getProperty('sf_nba:holding_food')), snoutVec);
  }
}
class bearHarvestGoal {
  static async searchForFood(bear, range, verticalRange) {
    try {
      if (!bear?.isValid()) return;
      --range; 
      --verticalRange;
      const center = {
        x: Math.floor(bear.location.x) + 0.5,
        y: Math.floor(bear.location.y),
        z: Math.floor(bear.location.z) + 0.5
      }, batchLimit = 27;
      let batchSize = 0;
      for (let x = center.x - range; x <= center.x + range; x++) {
        for (let y = center.y - verticalRange; y <= center.y + verticalRange; y++) {
          for (let z = center.z - range; z <= center.z + range; z++) {
            if (batchSize === batchLimit) {
              await new Promise(resolve => system.runTimeout(resolve));
              batchSize = 0;
            }
            batchSize++;
            const checkLocation = { x, y, z };
            const block = bear.dimension.getBlock(checkLocation);
            if (!block?.isValid() || !this.hasBearFood(block)) continue;
            bear.triggerEvent('sf_nba:move_to_harvest');
            if (bear.dimension.getEntitiesAtBlockLocation(checkLocation).some(e => e.typeId === 'sf_nba:bear_harvest_pathfinder')) return;
            return bear.dimension.spawnEntity('sf_nba:bear_harvest_pathfinder', checkLocation);
          }
        }
      }
    } catch (err) {}
  }
  static hasBearFood(block) {
    if (
      block.permutation.getState('growth') >= 2 && block.permutation.matches('minecraft:sweet_berry_bush') ||
      block.permutation.getState('honey_level') >= 5 && (block.permutation.matches('minecraft:beehive') || block.permutation.matches('minecraft:bee_nest'))
    ) return true;
  }
}
world.afterEvents.entityHitEntity.subscribe(data => {
  if (data.hitEntity?.typeId !== 'sf_nba:bear_harvest_pathfinder') return;
  const { damagingEntity: bear, hitEntity: harvest } = data;
  const harvestBlock = bear.dimension.getBlock(harvest.location);
  if (harvestBlock.permutation.matches('minecraft:sweet_berry_bush') && harvestBlock.permutation.getState('growth') >= 2) {
    const age = harvestBlock.permutation.getState('growth');
    const berryAmount = 1 + Math.floor(Math.random() * 2) + (age >= 3);
    harvestBlock.setPermutation(harvestBlock.permutation.withState('growth', 1));
    bear.dimension.spawnItem(new ItemStack('minecraft:sweet_berries', berryAmount), harvest.location);
    world.playSound('block.sweet_berry_bush.pick', bear.location);
  }
  else if (
    (harvestBlock.permutation.matches('minecraft:beehive') || harvestBlock.permutation.matches('minecraft:bee_nest')) &&
    harvestBlock.permutation.getState('honey_level') >= 5
  ) {
    harvestBlock.setPermutation(harvestBlock.permutation.withState('honey_level', 0));
    bear.dimension.spawnItem(new ItemStack('minecraft:honeycomb', 3), harvest.location);
    world.playSound('block.beehive.shear', bear.location);
  }
  harvest.remove();
}, {entityTypes: ['sf_nba:black_bear', 'sf_nba:grizzly_bear']});
world.afterEvents.dataDrivenEntityTrigger.subscribe(event => {
  const bear = event.entity;
  if (event.eventId === 'sf_nba:configure_eating') {
    let eatCounter = 0;
    const handleEating = system.runInterval(() => {
      if (!bear?.isValid() || !bear.dimension.getBlock(bear.location)?.isValid() || !(bear.getProperty('sf_nba:is_sitting') && bear.getProperty('sf_nba:holding_food'))) {
        if (bear?.isValid()) bear.triggerEvent('sf_nba:configure_holding_food_no_sitting');
        return system.clearRun(handleEating);
      }
      eatingEffects(bear, eatCounter);
      if (eatCounter > 40) {
        bear.runCommand('replaceitem entity @s slot.weapon.mainhand 0 air');
        system.run(() => bear.triggerEvent('sf_nba:on_eat'));
        return system.clearRun(handleEating);
      }
      eatCounter++;
    }, 0);
  }
  else if (event.eventId === 'sf_nba:harvest_sensor') {
    bearHarvestGoal.searchForFood(bear, 6, 3);
  }
}, {entityTypes: ['sf_nba:black_bear', 'sf_nba:grizzly_bear']});