import { DimensionTypes, EntityDamageCause, EquipmentSlot, MolangVariableMap, Player, system, world } from '@minecraft/server';
import WitherbossAttack from './witherbossAttack';
import { TargetController } from '../targets/targetController';
import WBVector3 from '../../util/wbVector3';
import { getItemInSlot } from '../../util/utils';
import { gaussianRandom, getRandomRange } from '../../util/random';
import { LONG_RANGE_SQ } from '../witherbossSettings';
const MAX_ATTACK_RANGE = 15;
function isUsingShield(entity) {
    if (!(entity instanceof Player))
        return false;
    if (!entity.isSneaking)
        return false;
    if (getItemInSlot(entity, EquipmentSlot.Offhand)?.typeId === 'minecraft:shield')
        return true;
    if (getItemInSlot(entity, EquipmentSlot.Mainhand)?.typeId === 'minecraft:shield')
        return true;
    return false;
}
// function findTargets(entity: Entity): Entity[] {
//   const headLocation = WBVector3.fromMC(entity.location);
//   return entity.dimension.getEntities({
//     location: headLocation,
//     families: ['player'],
//     excludeGameModes: [GameMode.spectator],
//     maxDistance: SOUL_FETCHER_MAX_RANGE,
//   })
//     .concat(entity.dimension.getEntities({
//       location: headLocation,
//       families: ['villager'],
//       maxDistance: SOUL_FETCHER_MAX_RANGE,
//     }))
//     .filter((target) => {
//       if (isUsingShield(target)) return false;
//       const offset = WBVector3.fromMC(target.getHeadLocation()).subtract(headLocation);
//       const direction = offset.normalize();
//       const viewDirection = WBVector3.fromMC(entity.getViewDirection());
//       const angle = direction.angleDegrees(viewDirection);
//       if (target instanceof Player) {
//         target.onScreenDisplay.setActionBar(WBVector2.fromMC(entity.getRotation()).toString());
//       }
//       return Math.abs(angle) < TARGET_CONE_ANGLE_DEGREES;
//     });
// }
export default class SoulFetcherAttack extends WitherbossAttack {
    onStart() {
        const entity = this.wither.getEntity();
        if (!entity)
            return;
        for (let i = 0; i < SoulFetcherAttack.NUM_SPAWNED_PER_ATTACK; i++) {
            const location = new WBVector3(gaussianRandom(), 0, gaussianRandom())
                .normalize()
                .multiply(getRandomRange(8, 20))
                .add({ x: 0, y: 10, z: 0 })
                .add(entity.location);
            try {
                const groundHit = entity.dimension.getBlockFromRay(location, { x: 0, y: -1, z: 0 }, {
                    includePassableBlocks: false,
                    includeLiquidBlocks: false,
                    maxDistance: 40,
                });
                if (groundHit) {
                    entity.dimension.playSound('twb_wisu:witherboss.attack.soul_fetcher.out', entity.location, { volume: 16 });
                    entity.dimension.spawnEntity('twb_wisu:soul_fetcher', new WBVector3(0, 1, 0).add(groundHit.block.bottomCenter()));
                }
            }
            catch (e) {
                // Ignore
            }
        }
    }
    tickAttack() {
    }
    endAttack() {
        return true;
    }
    static onTick() {
        for (const dimensionType of DimensionTypes.getAll()) {
            const dimension = world.getDimension(dimensionType.typeId);
            dimension.getEntities({
                type: 'twb_wisu:soul_fetcher',
                propertyOptions: [{ propertyId: 'twb_wisu:is_active', value: true }]
            }).forEach((e) => {
                const hadTarget = e.getProperty('twb_wisu:target_dist_ratio') > 0.0;
                const target = TargetController.get(e).getTarget();
                if (!target) {
                    // e.setProperty('twb_wisu:target_x_rotation', 0.0);
                    e.setProperty('twb_wisu:target_dist_ratio', 0.0);
                    if (system.currentTick % 60 === 0) {
                        if (Math.random() < 0.068) {
                            const numNearbyPlayers = e.dimension.getEntities({
                                location: e.location,
                                maxDistance: 20,
                                type: 'minecraft:player',
                            }).length;
                            if (numNearbyPlayers === 0) {
                                this.disappear(e);
                            }
                        }
                    }
                    return;
                }
                const headLocation = WBVector3.fromMC(e.location).add({ x: 0, y: 5, z: 0 });
                const headRotation = WBVector3.fromMC(target.location).subtract(headLocation).getRotation();
                e.setRotation(headRotation);
                const offset = headLocation.subtract(target.location);
                const distance = offset.length();
                // If target is too far away, do not impose any effects on the target
                if (distance > 15) {
                    e.setProperty('twb_wisu:target_dist_ratio', 0.0);
                    return;
                }
                // Play startup sound if target is acquired
                if (!hadTarget) {
                    e.dimension.playSound('twb_wisu:witherboss.attack.soul_fetcher.start', e.location, { volume: 16 });
                    this.recentlySoundPlayed.add(target);
                    system.runTimeout(() => this.recentlySoundPlayed.delete(target), 12);
                }
                else if (!this.recentlySoundPlayed.has(target)) {
                    // Play loop sound if target is still acquired and sound was not played recently
                    e.dimension.playSound('twb_wisu:witherboss.attack.soul_fetcher.suck', e.location, { volume: 16 });
                    this.recentlySoundPlayed.add(target);
                    system.runTimeout(() => this.recentlySoundPlayed.delete(target), 11);
                }
                const ratio = Math.max(1 - (distance / MAX_ATTACK_RANGE), 0.05);
                e.setProperty('twb_wisu:target_dist_ratio', ratio);
                // e.setProperty('twb_wisu:target_x_rotation', headRotation.x);
                // e.setProperty('twb_wisu:target_y_rotation', headRotation.y);
                // If target is using shield, do not impose any effects on the target
                if (isUsingShield(target))
                    return;
                const canGrab = distance < 2.5;
                if (canGrab) {
                    e.setProperty('twb_wisu:target_dist_ratio', 1.0);
                    this.grabTarget(e, target);
                }
                else {
                    target.applyKnockback(offset.x, offset.z, ratio > 0.4 ? 0.2 * ratio : 0.3 * ratio, ratio > 0.4 ? offset.y * 0.05 * ratio : Math.max(target.getVelocity().y * 0.7, 0));
                    const molangMap = new MolangVariableMap();
                    molangMap.setVector3('direction', offset.normalize());
                    molangMap.setFloat('distance', distance);
                    try {
                        dimension.spawnParticle('twb_wisu:soul_fetcher_effect', target.location, molangMap);
                        if (Math.random() < ratio) {
                            dimension.spawnParticle('twb_wisu:fetched_soul', target.location, molangMap);
                        }
                    }
                    catch (_) {
                        // Ignore
                    }
                }
            });
        }
    }
    static onHurt(entity) {
        if (entity.getProperty('twb_wisu:is_active'))
            this.disappear(entity);
    }
    static disappear(entity) {
        entity.setProperty('twb_wisu:is_active', false);
        system.runTimeout(() => {
            entity.dimension.playSound('twb_wisu:witherboss.attack.soul_fetcher.in', entity.location, { volume: 16 });
            entity.playAnimation('disappear', { controller: 'disappear' });
        }, 12);
        system.runTimeout(() => {
            if (entity.isValid())
                entity.triggerEvent('twb_wisu:despawn');
        }, 22);
    }
    static grabTarget(entity, target) {
        target.applyDamage(20, { cause: EntityDamageCause.contact, damagingEntity: entity });
        entity.playAnimation('bite', { controller: 'bite' });
        entity.dimension.runCommand('/stopsound @s twb_wisu:witherboss.attack.soul_fetcher.suck');
        entity.dimension.playSound('twb_wisu:witherboss.attack.soul_fetcher.bite', entity.location, { volume: 16 });
        this.disappear(entity);
        const isPlayer = (target instanceof Player);
        system.runTimeout(() => target.applyKnockback(0, 0, 0, -3), isPlayer ? 4 : 1);
    }
    static getAttackRegistry() {
        return {
            canStartAttack(wither) {
                const entity = wither.getEntity();
                if (!entity)
                    return false;
                return (wither.getTargetController().getNumTargets() > 0
                    && entity.dimension.getEntities({
                        location: entity.location,
                        maxDistance: Math.sqrt(LONG_RANGE_SQ),
                        type: 'twb_wisu:soul_fetcher',
                    }).length < SoulFetcherAttack.NUM_MAX_ALIVE);
            },
            attackChance: 0.007,
            createNewAttack(wither) {
                return new SoulFetcherAttack(wither);
            }
        };
    }
}
SoulFetcherAttack.NUM_SPAWNED_PER_ATTACK = 1;
SoulFetcherAttack.NUM_MAX_ALIVE = 3;
// Set containing all players for whom a soul fetcher sound was recently played
SoulFetcherAttack.recentlySoundPlayed = new Set();
