import BaseBoss from '../BaseBoss';
import { world, system, EntityDamageCause } from "@minecraft/server";
import * as utils from "../misc";
import { startCoroutineForBoss } from "../CoroutineClass";
import { randomInt } from '../../utils/index';

const ABILITY_COOLDOWN_CONFIG = new Map([
  ["range", 2000],
  ["roar", 2000]
]);

class Skulkosaurus extends BaseBoss {
  abilityCd;
  isSubscribed = false;

  constructor(entityId) {
    super('Skulkosaurus', entityId);
    this.abilityCd = new Map();
  }

  async specialBehavior() {
    if (!this.isSubscribed) {
      world.afterEvents.dataDrivenEntityTrigger.subscribe((args) => {
        const { entity, eventId } = args;
        if (!this.entity.isValid()) return;
        if (entity.id === this.entityId) {
          switch (eventId) {
            case 'lv_mo:attack':
              this.basic_attack();
              break;
            case 'lv_mo:range':
              this.rangeAttack();
              break;
            case 'lv_mo:roar':
              this.roarAttack();
              break;
          }
        }
      });
      this.isSubscribed = true
    }
    this.tryActiveAbility();
  }

  async tryActiveAbility() {
    // Check each ability's cooldown status
    ABILITY_COOLDOWN_CONFIG.forEach((cooldownTime, abilityId) => {
      if (!this.entity.isValid()) return;
      if (this.isAbilityReady(abilityId)) {
        this.entity.removeTag(abilityId);
        this.abilityCd.set(abilityId, Date.now());  // Update cooldown timestamp after tag removal
      }
    });
  }

  // Helper function to check if an ability's cooldown has expired
  isAbilityReady(abilityId) {
    const now = Date.now();
    const lastUsed = this.abilityCd.get(abilityId) || 0;
    const cooldownTime = ABILITY_COOLDOWN_CONFIG.get(abilityId) || 0;
    //console.warn(abilityId, ' = ', (now - lastUsed), ' > ', cooldownTime)
    return (now - lastUsed) >= cooldownTime;
  }

  BASIC_ATTACK_DURATION = 1.25 * 20;
  BASIC_ATTACK_TIME = 0.5 * 20;
  BASIC_ATTACK_RADIUS = 5;
  BASIC_ATTACK_DAMAGE = randomInt(15,20);
  async basic_attack() {
    if (!this.entity.isValid()) return;
    this.entity.setProperty('lv_mo:animations', 'attack');
    utils.facePlayer(this.entity, 1);
    if (!this.entity.isValid()) return;
    let victims = utils.getRadiusEntity(this.entity, utils.getPosForward(this.entity, 2), this.BASIC_ATTACK_RADIUS, ['player']);
    utils.delayExecute(this.BASIC_ATTACK_TIME, () => {
      if (!this.entity.isValid()) return;
      for (let victim of victims) {
        if (!this.entity.isValid()) return;
        victim.applyDamage(this.BASIC_ATTACK_DAMAGE, {
          cause: EntityDamageCause.entityAttack,
          damagingEntity: this.entity,
        });
      }
    });
    await this.wait(this.BASIC_ATTACK_DURATION - this.BASIC_ATTACK_TIME);
    await this.resetAndReadyAbility();
  }

  RANGE_ATTACK_DURATION = 1.875 * 20;
  RANGE_ATTACK_TIME = 0.67 * 20;
  RANGE_ATTACK_TIP_DURATION = 2 * 20;
  RANGE_ATTACK_DAMAGE = randomInt(16,18);
  async rangeAttack() {
    this.tipPlayer(15, 'avoid the range attack');
    let i = 0;
    const facePlayerInterval = system.runInterval(() => {
      if (!this.entity.isValid() || i >= this.RANGE_ATTACK_TIP_DURATION) {
        system.clearRun(facePlayerInterval);
      }
      this.entity.runCommand("/execute as @s facing entity @p eyes run tp @s ~ ~ ~ ~ ~");
      i++;
    }, 1);

    let active = function* () {
      if (!this.entity.isValid()) return;
      yield this.RANGE_ATTACK_TIP_DURATION;
      utils.facePlayer(this.entity, 1);
      this.entity.setProperty('lv_mo:animations', 'range');
      yield this.RANGE_ATTACK_TIME;

      if (!this.entity.isValid()) return;
      let victims = utils.getRadiusEntity(this.entity, utils.getPosForward(this.entity, 2), 14, ['player']);
      for (let victim of victims) {
        if (victim.id === this.entity.id) return;
        if (!this.entity.isValid()) return;
        utils.effect(victim, 'nausea', 8, 3)
        utils.setPosKnockback(victim, this.entity.location, [5,0.8])
        victim.applyDamage(this.RANGE_ATTACK_DAMAGE, {
          cause: EntityDamageCause.entityAttack,
          damagingEntity: this.entity,
        });
      }

      const cooldownTime = ABILITY_COOLDOWN_CONFIG.get('range')
      yield (this.RANGE_ATTACK_DURATION - this.RANGE_ATTACK_TIME);
      this.entity.addTag('range');
      this.abilityCd.set("range", Date.now() + 100 * this.RANGE_ATTACK_DURATION + cooldownTime);
    }.bind(this);

    const key = startCoroutineForBoss(active, () => {
      this.resetAndReadyAbility();
    }, this.entity.id);
  }

  ROAR_ATTACK_DURATION = 2.5 * 20;
  ROAR_ATTACK_TIME = 0.88 * 20;
  ROAR_ATTACK_TIP_DURATION = 2 * 20;
  ROAR_ATTACK_RADIUS = 25
  async roarAttack() {
    this.tipPlayer(15, 'Move Away');
    utils.facePlayer(this.entity, this.ROAR_ATTACK_TIP_DURATION);

    let active = function* () {
      if (!this.entity.isValid()) return;
      yield this.ROAR_ATTACK_TIP_DURATION;
      this.entity.setProperty('lv_mo:animations', 'roar');
      yield this.ROAR_ATTACK_TIME;
      if (!this.entity.isValid()) return;
      let victims = utils.getRadiusEntity(this.entity, utils.getPosForward(this.entity, 2), this.ROAR_ATTACK_RADIUS, ['player']);
      if (!this.entity.isValid()) return;
      const maxDistance = this.ROAR_ATTACK_RADIUS; // Define the maximum distance for full knockback and camerashake
      const maxIntensity = 1.5; // Maximum intensity at zero distance for camerashake
      const maxDuration = 3;  // Maximum duration at zero distance for camerashake
      const maxKnockbackPower = 7; // Maximum knockback power
      const maxVerticalKnockback = 1; // Maximum vertical knockback power

      for (let victim of victims) {
        if (victim.id === this.entity.id) return;

        const distance = utils.calculateDistance(this.entity.location, victim.location);

        if (distance < maxDistance) {
          // Calculate intensity and duration scaling based on distance
          const distanceFactor = 1 - (distance / maxDistance); // Closer is higher

          // Scaled intensity and duration for camerashake
          const intensity = maxIntensity * distanceFactor;
          const duration = maxDuration * distanceFactor;

          // Apply camerashake with scaled intensity and duration
          if (!this.entity.isValid()) return;
          victim.runCommand(`camerashake add @s ${intensity} ${duration} positional`);
          victim.runCommand(`damage @s 16 entity_attack`);

          // Scaled knockback power based on distance
          const knockbackPower = maxKnockbackPower * distanceFactor;
          const verticalKnockback = maxVerticalKnockback * distanceFactor;

          // Apply knockback with scaled power
          if (!this.entity.isValid()) return;
          utils.setPosKnockback(victim, this.entity.location, [knockbackPower, verticalKnockback]);

          //console.warn(`Distance to victim: ${distance}`);
          //console.warn(`Intensity to victim: ${intensity}`);
          //console.warn(`Duration to victim: ${duration}`);
          //console.warn(`KnockbackPower to victim: ${knockbackPower}`);
          //console.warn(`VerticalKnockback to victim: ${verticalKnockback}`);
        }
      }


      const cooldownTime = ABILITY_COOLDOWN_CONFIG.get('roar')
      yield (this.ROAR_ATTACK_DURATION - this.ROAR_ATTACK_TIME);
      if (!this.entity.isValid()) return;
      this.entity.addTag('roar');
      this.abilityCd.set("roar", Date.now() + 100 * this.ROAR_ATTACK_DURATION + cooldownTime);
    }.bind(this);

    const key = startCoroutineForBoss(active, () => {
      this.resetAndReadyAbility();
    }, this.entity.id);
  }
}

export default Skulkosaurus;
