package zenith.zov.client.modules.impl.combat;

import com.darkmagician6.eventapi.EventManager;
import com.darkmagician6.eventapi.EventTarget;
import net.minecraft.entity.Entity;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Hand;
import net.minecraft.util.math.Vec3d;
import zenith.zov.base.events.impl.player.EventUpdate;
import zenith.zov.client.modules.api.Category;
import zenith.zov.client.modules.api.Module;
import zenith.zov.client.modules.api.ModuleAnnotation;
import zenith.zov.client.modules.api.setting.impl.BooleanSetting;
import zenith.zov.client.modules.api.setting.impl.NumberSetting;

@ModuleAnnotation(
    name = "MaceAura",
    description = "Attack targets with mace only when falling in air",
    category = Category.COMBAT
)
public class MaceAura extends Module {
    private final NumberSetting range = new NumberSetting("Range", 4.5F, 1.0F, 6.0F, 0.1F);
    private final NumberSetting fallDistance = new NumberSetting("Min Fall Distance", 1.0F, 0.0F, 10.0F, 0.1F);
    private final NumberSetting attackSpeed = new NumberSetting("Attack Speed", 20.0F, 1.0F, 50.0F, 1.0F);
    private final BooleanSetting targetPlayers = new BooleanSetting("Target Players", true);
    private final BooleanSetting targetMobs = new BooleanSetting("Target Mobs", true);
    private final BooleanSetting requireMace = new BooleanSetting("Require Mace", true);
    private final BooleanSetting autoSwitch = new BooleanSetting("Auto Switch to Mace", true);
    private long lastAttackTime = 0L;

    public MaceAura() {
        EventManager.register(this);
    }

    @EventTarget
    public void onUpdate(EventUpdate event) {
        if (mc.player != null && mc.world != null && mc.interactionManager != null) {
            if (!mc.player.isOnGround() && !(mc.player.fallDistance < this.fallDistance.getCurrent())) {
                if (!this.requireMace.isEnabled() || this.hasMaceInHand() || this.hasMaceInInventory()) {
                    if (this.autoSwitch.isEnabled() && !this.hasMaceInHand() && this.hasMaceInInventory()) {
                        this.switchToMace();
                    }

                    long currentTime = System.currentTimeMillis();
                    if (!((float)(currentTime - this.lastAttackTime) < 1000.0F / this.attackSpeed.getCurrent())) {
                        Entity target = this.findTarget();
                        if (target != null) {
                            this.attackTarget(target);
                            this.lastAttackTime = currentTime;
                        }
                    }
                }
            }
        }
    }

    private boolean hasMaceInHand() {
        if (mc.player.getMainHandStack().isEmpty()) {
            return false;
        } else {
            String itemName = mc.player.getMainHandStack().getItem().toString().toLowerCase();
            return itemName.contains("mace");
        }
    }

    private boolean hasMaceInInventory() {
        for (int i = 0; i < 9; i++) {
            if (!mc.player.getInventory().getStack(i).isEmpty()) {
                String itemName = mc.player.getInventory().getStack(i).getItem().toString().toLowerCase();
                if (itemName.contains("mace")) {
                    return true;
                }
            }
        }

        return false;
    }

    private void switchToMace() {
        for (int i = 0; i < 9; i++) {
            if (!mc.player.getInventory().getStack(i).isEmpty()) {
                String itemName = mc.player.getInventory().getStack(i).getItem().toString().toLowerCase();
                if (itemName.contains("mace")) {
                    mc.player.getInventory().setSelectedSlot(i);
                    break;
                }
            }
        }
    }

    private Entity findTarget() {
        Iterable<Entity> entities = mc.world.getEntities();
        Entity closestTarget = null;
        double closestDistance = (double)this.range.getCurrent();

        for (Entity entity : entities) {
            if (entity != mc.player && entity.isAlive() && this.isValidTarget(entity)) {
                double distance = (double)mc.player.distanceTo(entity);
                if (!(distance > (double)this.range.getCurrent()) && !(entity.getY() >= mc.player.getY()) && distance < closestDistance) {
                    closestDistance = distance;
                    closestTarget = entity;
                }
            }
        }

        return closestTarget;
    }

    private boolean isValidTarget(Entity entity) {
        if (entity instanceof PlayerEntity) {
            return this.targetPlayers.isEnabled();
        } else {
            return entity instanceof MobEntity ? this.targetMobs.isEnabled() : false;
        }
    }

    private void attackTarget(Entity target) {
        Vec3d targetPos = target.getEyePos();
        Vec3d playerPos = mc.player.getEyePos();
        Vec3d direction = targetPos.subtract(playerPos).normalize();
        float yaw = (float)Math.toDegrees(Math.atan2(-direction.x, direction.z));
        float pitch = (float)Math.toDegrees(Math.asin(-direction.y));
        mc.player.setYaw(yaw);
        mc.player.setPitch(pitch);
        mc.interactionManager.attackEntity(mc.player, target);
        mc.player.swingHand(Hand.MAIN_HAND);
    }
}
