import { LocationInUnloadedChunkError, LocationOutOfWorldBoundariesError, system } from '@minecraft/server';
import HeadAttack from './headAttack';
import { IMMUNE_ATTACK_ENTITIES, SHORT_RANGE_SQ } from '../witherbossSettings';
import WBVector3 from '../../util/wbVector3';
export default class FireBreathAttack extends HeadAttack {
    constructor(wither, headPos) {
        super(wither, headPos);
        // The time in ticks until the head will attack again
        this.attackCooldown = 0;
        this.resetAttackCooldown();
    }
    /// Override methods
    resumeHeadAttackMode() {
    }
    tickHeadAttack() {
    }
    tickHeadAttackWhenActive() {
        // Update the properties for target yaw and pitch
        if (this.target && this.target.isValid()) {
            const headLocation = this.getApproxIdleHeadLocation(this.headPos);
            if (!headLocation) {
                return false;
            }
            const targetLocation = WBVector3.fromMC(this.target.location);
            const direction = targetLocation.subtract(headLocation).normalize().getRotation();
            const entity = this.wither.getEntity();
            if (entity) {
                entity.setProperty(this.headTargetYawPropertyName, direction.y);
                entity.setProperty(this.headTargetPitchPropertyName, direction.x);
            }
        }
        // If an attack was launched, do not do anything else
        if (this.attackCooldown < 0) {
            return true;
        }
        // Determine target
        this.target = this.getNearestTarget(this.headPos, SHORT_RANGE_SQ, 80);
        if (!this.target) {
            return false;
        }
        // If the cooldown is 0, start an attack
        if (this.attackCooldown === 0) {
            this.launchAttack(this.target);
        }
        // Decrement the attack cooldown
        this.attackCooldown--;
        return this.attackCooldown < 0;
    }
    pauseHeadAttackMode() {
    }
    stopHeadAttack() {
    }
    resetAttackCooldown() {
        const cooldown = Math.random()
            * (FireBreathAttack.MAX_ATTACK_COOLDOWN - FireBreathAttack.MIN_ATTACK_COOLDOWN)
            + FireBreathAttack.MIN_ATTACK_COOLDOWN;
        this.attackCooldown = Math.floor(cooldown);
    }
    launchAttack(target) {
        // Determine the direction to the target
        const { dimension } = target;
        let headLoc = this.getApproxIdleHeadLocation(this.headPos);
        if (!headLoc) {
            return;
        }
        headLoc = headLoc.subtract({ x: 0, y: 2, z: 0 });
        const directionToTarget = WBVector3.fromMC(target.location).subtract(headLoc).normalize();
        // Send fire breaths in the direction of the target (cone-shaped)
        for (let distance = 1; distance < FireBreathAttack.ATTACK_DISTANCE; distance++) {
            const breathLocation = headLoc.add(directionToTarget.multiply(distance));
            system.runTimeout(() => {
                const numParticles = distance * 5;
                for (let i = 0; i < numParticles; i++) {
                    this.spawnFireBreath(dimension, breathLocation, 1.0 + distance / 4);
                }
            }, Math.floor(10 + distance * FireBreathAttack.FLAME_SPEED));
        }
        // Reset the attack cooldown after the attack is finished
        system.runTimeout(() => {
            this.resetAttackCooldown();
        }, FireBreathAttack.TOTAL_ATTACK_TIME);
        // Play the animation
        this.wither.getEntity()?.playAnimation('animation.twb_wisu.wither_wraith.base_attack_center');
        // Play the sound
        dimension.playSound('twb_wisu:witherboss.attack.fire_breath', headLoc, {
            volume: 16
        });
    }
    spawnFireBreath(dimension, location, randomnessFactor) {
        const randomOffset = new WBVector3(Math.random() * 1.5 * randomnessFactor - 0.75, Math.random() * 0.8 * randomnessFactor - 0.4, Math.random() * 1.5 * randomnessFactor - 0.75);
        const newLocation = randomOffset.add(location);
        // Spawn particle at new location
        dimension.spawnParticle('minecraft:blue_flame_particle', newLocation);
        // Fire up entities at the location
        dimension.getEntitiesAtBlockLocation(newLocation).forEach((entity) => {
            if (!IMMUNE_ATTACK_ENTITIES.includes(entity.typeId)) {
                entity.setOnFire(7, false);
                entity.applyDamage(6);
            }
        });
        // Make the blocks at the location flamed (randomly)
        if (Math.random() < 0.2) {
            try {
                const block = dimension.getBlock(newLocation);
                const isSolid = !!block?.dimension.getBlockFromRay(block.location, { x: 0, y: 1, z: 0 }, { includePassableBlocks: false, maxDistance: 1 });
                const above = block?.above();
                if (block && isSolid && above && above.isAir
                    && FireBreathAttack.FLAMMABLE_BLOCKS.includes(block.typeId)) {
                    block.setType('minecraft:soul_soil');
                    above.setType('minecraft:soul_fire');
                }
            }
            catch (e) {
                // Ignore block access exceptions
                // eslint-disable-next-line max-len
                if (!(e instanceof LocationInUnloadedChunkError || e instanceof LocationOutOfWorldBoundariesError)) {
                    throw e;
                }
            }
        }
    }
}
/// Static constants for the shoot head attack
FireBreathAttack.MIN_ATTACK_COOLDOWN = 20;
FireBreathAttack.MAX_ATTACK_COOLDOWN = 80;
FireBreathAttack.TOTAL_ATTACK_TIME = 100;
// Distance in blocks that the fire breaths will travel
FireBreathAttack.ATTACK_DISTANCE = 18;
// Speed of the fire breath (higher is slower actually lol)
FireBreathAttack.FLAME_SPEED = 1;
// Blocks that can be turned into soul soil and soul fire
FireBreathAttack.FLAMMABLE_BLOCKS = [
    'minecraft:grass',
    'minecraft:dirt',
    'minecraft:sand',
    'minecraft:coarse_dirt',
    'minecraft:podzol',
    'minecraft:soul_sand',
    'minecraft:soul_soil',
    'twb_wisu:wilt_block',
    'twb_wisu:withered_stone_block'
];
