package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.towers;

import net.minestom.server.collision.Aerodynamics;
import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityProjectile;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.attribute.Attribute;
import net.minestom.server.event.entity.projectile.ProjectileCollideWithBlockEvent;
import net.minestom.server.event.entity.projectile.ProjectileCollideWithEntityEvent;
import org.jetbrains.annotations.NotNull;

import java.time.Duration;

public abstract class ShootingTower extends Tower {
    public ShootingTower(@NotNull EntityType entityType, int damage, double attacksPerSecond, int range) {
        super(entityType, damage, attacksPerSecond, range);
    }

    protected void shootProjectile(EntityCreature enemy, EntityType projectileType, double power, double spread) {
        EntityProjectile projectile = new EntityProjectile(this, projectileType);
        projectile.setView(this.getPosition().yaw(), this.getPosition().pitch());
        projectile.setNoGravity(true);
        projectile.setAerodynamics(new Aerodynamics(0, 1, 1));
        Pos startingPoint = this.getPosition().add(0, this.getEyeHeight(), 0);

        double enemySpeed = enemy.getAttribute(Attribute.MOVEMENT_SPEED).getBaseValue() / 0.05;
        Point enemyGoal = enemy.getNavigator().getGoalPosition();
        if(enemyGoal == null) enemyGoal = enemy.getPosition();
        Pos enemyPosition = enemy.getPosition();
        Vec enemyMovement = Vec.fromPoint(enemyGoal.sub(enemyPosition)).normalize().mul(enemySpeed);

        // just an approximation, not calculated correctly:
        double projectileSpeed = 20 * power;
        double enemyTowerDistance = startingPoint.distance(enemyPosition);
        double estimatedFlightTime = (enemyTowerDistance / projectileSpeed);
        Pos targetPosition = enemyPosition.add(enemyMovement.mul(estimatedFlightTime)).withY(enemyPosition.y()+enemy.getEyeHeight());

        projectile.shoot(targetPosition, power, spread);
        projectile.scheduleRemove(Duration.ofSeconds(5));
        projectile.setInstance(this.getInstance(), startingPoint);
        projectile.eventNode()
            .addListener(ProjectileCollideWithEntityEvent.class, event -> {
                if(!(event.getTarget() instanceof EntityCreature target)) return;
                if(!this.getRoomInstance().getEnemies().contains(target)) return;
                this.causeDamage(target);
                this.onProjectileHit(target);
                target.setFlyingWithElytra(true);
                projectile.remove();
            })
            .addListener(ProjectileCollideWithBlockEvent.class, event -> projectile.remove());
    }

    protected void onProjectileHit(EntityCreature enemy) {
    }

    @Override
    protected void attack(EntityCreature enemy) {
        this.shootProjectile(enemy, EntityType.ARROW, 2, 0);
    }
}
