package com.thebrokenrail.twine.mixin;

import com.thebrokenrail.twine.component.StageDataComponent;
import com.thebrokenrail.twine.entity.ExplodeArtificialBlockGoal;
import com.thebrokenrail.twine.entity.FleeEndRodGoal;
import com.thebrokenrail.twine.entity.FollowPassiveEntityGoal;
import com.thebrokenrail.twine.entity.StandOnGlowingObsidianGoal;
import com.thebrokenrail.twine.util.StageUtil;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.ai.goal.FollowTargetGoal;
import net.minecraft.entity.ai.goal.GoalSelector;
import net.minecraft.entity.mob.CreeperEntity;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.mob.MobEntityWithAi;
import net.minecraft.entity.mob.Monster;
import net.minecraft.entity.passive.IronGolemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.Random;

@SuppressWarnings("ConstantConditions")
@Mixin(MobEntity.class)
public class MixinMobEntity {
    @Shadow
    @Final
    protected GoalSelector targetSelector;
    @Shadow
    @Final
    protected GoalSelector goalSelector;

    @Inject(at = @At("RETURN"), method = "<init>")
    public void initGoals(EntityType<? extends MobEntity> entityType, World world, CallbackInfo info) {
        if (world != null && !world.isClient()) {
            if (this instanceof Monster) {
                if ((Object) this instanceof MobEntityWithAi) {
                    goalSelector.add(1, new StandOnGlowingObsidianGoal((MobEntityWithAi) (Object) this));
                    goalSelector.add(3, new FleeEndRodGoal((MobEntityWithAi) (Object) this));
                    if ((Object) this instanceof CreeperEntity) {
                        goalSelector.add(3, new ExplodeArtificialBlockGoal((MobEntityWithAi) (Object) this));
                    }
                }
                targetSelector.add(2, new FollowPassiveEntityGoal((MobEntity) (Object) this));
            } else if ((Object) this instanceof IronGolemEntity) {
                targetSelector.add(3, new FollowTargetGoal<>((IronGolemEntity) (Object) this, PlayerEntity.class, 10, true, false, entity -> {
                    StageDataComponent component = StageDataComponent.getFromWorld((ServerWorld) ((IronGolemEntity) (Object) this).getEntityWorld());
                    BlockPos blockPos = ((IronGolemEntity) (Object) this).getBlockPos();
                    int stage = component.findEffectiveStageOfChunk((ServerWorld) (((IronGolemEntity) (Object) this).getEntityWorld()), blockPos);

                    return stage >= StageUtil.IRON_GOLEMS_TARGET_PLAYERS && !((IronGolemEntity) (Object) this).isPlayerCreated();
                }));
            }
        }
    }

    @Inject(at = @At("HEAD"), method = "isInDaylight", cancellable = true)
    public void isInDaylight(CallbackInfoReturnable<Boolean> info) {
        if (!((MobEntity) (Object) this).getEntityWorld().isClient()) {
            StageDataComponent component = StageDataComponent.getFromWorld((ServerWorld) ((MobEntity) (Object) this).getEntityWorld());
            BlockPos blockPos = ((MobEntity) (Object) this).getBlockPos();
            int stage = component.findEffectiveStageOfChunk((ServerWorld) ((MobEntity) (Object) this).getEntityWorld(), blockPos);
            if (stage >= StageUtil.MOBS_NO_LONGER_BURN_IN_SUNLIGHT) {
                info.setReturnValue(false);
            }
        }
    }

    @Redirect(at = @At(value = "INVOKE", target = "Ljava/util/Random;nextFloat()F", ordinal = 0), method = "initEquipment", allow = 1)
    public float initEquipment(Random random) {
        StageDataComponent component = StageDataComponent.getFromWorld((ServerWorld) ((MobEntity) (Object) this).getEntityWorld());
        BlockPos blockPos = ((MobEntity) (Object) this).getBlockPos();
        int stage = component.findEffectiveStageOfChunk((ServerWorld) ((MobEntity) (Object) this).getEntityWorld(), blockPos);
        if (stage >= StageUtil.MOBS_GUARANTEED_ARMOR) {
            return -1f;
        } else {
            return random.nextFloat();
        }
    }
}
