package net.Chipperfluff.chipi.entity;

import net.minecraft.block.BlockState;
import net.minecraft.block.SlabBlock;
import net.minecraft.block.StairsBlock;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.goal.*;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.mob.PathAwareEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.sound.SoundCategory;
import net.minecraft.state.property.Properties;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

import net.Chipperfluff.chipi.armor.ProtectionAuraHandler;
import net.Chipperfluff.chipi.item.ModItems;
import net.Chipperfluff.chipi.sound.ModSounds;
import net.Chipperfluff.chipi.util.TickScheduler;

public class MepEntity extends PathAwareEntity {

    private static final int FORGET_TARGET_AFTER_TICKS = 100;
    private static final int DESPAWN_DISTANCE = 300;

    private boolean angryAtPlayer = false;
    private int ticksSinceLastSeen = 0;

    public MepEntity(EntityType<? extends PathAwareEntity> entityType, World world) {
        super(entityType, world);
    }

    // === AI ===

    @Override
    protected void initGoals() {
        this.goalSelector.add(1, new SwimGoal(this));
        this.goalSelector.add(2, new MeleeAttackGoal(this, 1.2D, true));
        this.goalSelector.add(3, new WanderAroundFarGoal(this, 1.0D));
        this.goalSelector.add(4, new LookAtEntityGoal(this, PlayerEntity.class, 8.0F));
        this.goalSelector.add(5, new LookAroundGoal(this));

        this.targetSelector.add(
            1,
            new ActiveTargetGoal<>(
                this,
                PlayerEntity.class,
                true,
                target -> target instanceof PlayerEntity player
                    && !isHardIgnored(player)
            )
        );
    }

    public static DefaultAttributeContainer.Builder createMepAttributes() {
        return PathAwareEntity.createMobAttributes()
            .add(EntityAttributes.GENERIC_MAX_HEALTH, 20.0)
            .add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 4.0)
            .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25)
            .add(EntityAttributes.GENERIC_FOLLOW_RANGE, 32.0);
    }

    // === Combat memory ===

    @Override
    public boolean damage(DamageSource source, float amount) {
        if (source.getAttacker() instanceof PlayerEntity) {
            angryAtPlayer = true;
            ticksSinceLastSeen = 0;
        }
        return super.damage(source, amount);
    }

    // === ATTACK OVERRIDE (AURA IMMUNITY) ===

    @Override
    public boolean tryAttack(Entity target) {
        if (target instanceof PlayerEntity player) {
            if (ProtectionAuraHandler.hasAura(player)) {
                return false; // chase but never hit
            }
        }
        return super.tryAttack(target);
    }

    @Override
    public void tick() {
        super.tick();

        // --- DISTANCE DESPAWN ONLY ---
        if (!this.getWorld().isClient && isTooFarFromAllPlayers()) {
            this.discard();
            return;
        }

        LivingEntity target = this.getTarget();

        if (!(target instanceof PlayerEntity player)) {
            angryAtPlayer = false;
            ticksSinceLastSeen = 0;
            return;
        }

        if (isHardIgnored(player)) {
            clearTarget();
            return;
        }

        if (this.canSee(player)) {
            ticksSinceLastSeen = 0;
            angryAtPlayer = true;
            this.getNavigation().startMovingTo(player, 1.2D);
        } else {
            ticksSinceLastSeen++;
            if (ticksSinceLastSeen <= FORGET_TARGET_AFTER_TICKS) {
                this.getNavigation().startMovingTo(player, 1.2D);
            } else {
                clearTarget();
            }
        }
    }

    private void clearTarget() {
        angryAtPlayer = false;
        ticksSinceLastSeen = 0;
        this.setTarget(null);
        this.getNavigation().stop();
    }

    // === DISTANCE CHECK ===

    private boolean isTooFarFromAllPlayers() {
        double maxSq = DESPAWN_DISTANCE * DESPAWN_DISTANCE;

        for (PlayerEntity player : this.getWorld().getPlayers()) {
            if (this.squaredDistanceTo(player) <= maxSq) {
                return false;
            }
        }
        return true;
    }

    // === HARD IGNORE RULES ===

    private static boolean isHardIgnored(PlayerEntity player) {
        if (player.getZ() < 18) return true;
        return isOnProtectedBlock(player);
    }

    private static boolean isOnProtectedBlock(PlayerEntity player) {
        BlockPos pos = player.getBlockPos();
        BlockState state = player.getWorld().getBlockState(pos);

        if (!state.contains(Properties.WATERLOGGED) || !state.get(Properties.WATERLOGGED)) {
            return false;
        }

        return state.getBlock() instanceof StairsBlock
            || state.getBlock() instanceof SlabBlock;
    }

    // === MILKING ===

    @Override
    public ActionResult interactMob(PlayerEntity player, Hand hand) {
        ItemStack stack = player.getStackInHand(hand);

        if (stack.isOf(Items.BUCKET) && !this.isBaby()) {
            if (!player.getWorld().isClient) {

                stack.decrement(1);
                player.giveItemStack(new ItemStack(ModItems.MEP_MILK));

                float basePitch = 0.3f + this.random.nextFloat() * 1.9f;
                float baseVolume = 0.9f + this.random.nextFloat() * 0.6f;

                this.getWorld().playSound(
                    null,
                    this.getBlockPos(),
                    ModSounds.MEP_MILK,
                    SoundCategory.NEUTRAL,
                    baseVolume,
                    basePitch
                );

                if (this.random.nextFloat() < 0.10f) {
                    int delay = 10 + this.random.nextInt(21);

                    float echoPitch = basePitch * 0.5f;
                    float echoVolume = baseVolume * 0.5f;

                    TickScheduler.schedule(delay, () -> {
                        if (!this.isAlive()) return;

                        this.getWorld().playSound(
                            null,
                            this.getBlockPos(),
                            ModSounds.MEP_MILK,
                            SoundCategory.NEUTRAL,
                            echoVolume,
                            echoPitch
                        );
                    });
                }
            }
            return ActionResult.SUCCESS;
        }

        return super.interactMob(player, hand);
    }
}
