package xyz.illuc.neuralgiacore.events;

import net.adinvas.prototype_pain.limbs.Limb;
import net.adinvas.prototype_pain.limbs.PlayerHealthData;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingDamageEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import xyz.illuc.neuralgiacore.entities.OfflinePlayerEntity;

import java.util.Optional;
import java.util.UUID;

@Mod.EventBusSubscriber(modid = "neuralgiacore", bus = Mod.EventBusSubscriber.Bus.FORGE)
public class OfflinePlayerEvents {

    @SubscribeEvent
    public static void onPlayerLogOut(PlayerEvent.PlayerLoggedOutEvent event) {
        ServerPlayer player = (ServerPlayer) event.getEntity();

        System.out.println("event triggered");

        player.level().addFreshEntity(OfflinePlayerEntity.createFromPlayer(player));
    }

    @SubscribeEvent
    public static void onPlayerLogIn(PlayerEvent.PlayerLoggedInEvent event) {
        if (!(event.getEntity() instanceof ServerPlayer)) {
            return;
        }
        ServerPlayer player = (ServerPlayer) event.getEntity();
        System.out.println("event triggered");

        boolean foundPlayer = false;
        for (ServerLevel world : player.level().getServer().getAllLevels()) {
            Optional<OfflinePlayerEntity> persistentPlayer = findPersistentPlayer(world, player.getUUID());

            if (persistentPlayer.isPresent()) {
                System.out.println("Player present");
                OfflinePlayerEntity p = persistentPlayer.get();
                p.toPlayer(player);
                p.remove(Entity.RemovalReason.DISCARDED);
                foundPlayer = true;
                break;
            }
        }
        if (!foundPlayer) {
            System.out.println("Player not found!");
        }

    }

    public static Optional<OfflinePlayerEntity> findPersistentPlayer(ServerLevel world, UUID playerUUID) {
        for (net.minecraft.world.entity.Entity entity : world.getAllEntities()) {
            if (entity instanceof OfflinePlayerEntity offlinePlayer) {
                if (offlinePlayer.getPlayerUUID().isPresent() &&
                        offlinePlayer.getPlayerUUID().get().equals(playerUUID)) {
                    return Optional.of(offlinePlayer);
                }
            }
        }
        return Optional.empty();
    }

    @SubscribeEvent
    public static void onLivingDamage(LivingDamageEvent event) {
        if (!(event.getEntity() instanceof OfflinePlayerEntity player)) return;
        if (event.isCanceled()) return;

        PlayerHealthData ph = player.getPlayerHealthData();


        int i = 0;
        float damage = event.getAmount();
        ph.setAdrenaline(Math.max(ph.getAdrenaline(), damage * 1.0F));
        while(damage > 0.0F) {
            ++i;
            Limb randLimb = Limb.weigtedRandomLimb();
            float damage_pass = (float)(Math.random() * (double)4.0F);
            if (damage_pass > damage) {
                damage_pass = damage;
            }

            float passDamage = damage;

            ph.applyPain(randLimb, ph.painFromDamage((float)((double)passDamage * (Math.random() / (double)2.0F + (double)1.0F))));
            ph.applyMuscleDamage(randLimb, (float)((double)passDamage * (Math.random() / (double)2.0F + (double)0.5F)), (Player) event.getSource().getEntity());
            ph.applySkinDamage(randLimb, (float)((double)passDamage * (Math.random() / (double)2.0F + (double)0.5F)));
            if (Math.random() < (double)i * 0.2) {
                ph.applyPain(randLimb, ph.painFromDamage((float)((double)passDamage * (Math.random() / (double)2.0F + (double)1.5F))));
                ph.applyMuscleDamage(randLimb, (float)((double)passDamage * (Math.random() / (double)2.0F + (double)0.7F)), (Player) event.getSource().getEntity());
                ph.applySkinDamage(randLimb, (float)((double)passDamage * (Math.random() / (double)2.0F + (double)0.7F)));
                ph.applyBleedDamage(randLimb, (float)((double)passDamage * (Math.random() / (double)2.0F + (double)0.7F)), null);
                damage -= damage_pass;
            }

            damage -= damage_pass;
            boolean amputated = ph.handleAmputation(randLimb, passDamage, 26.0F, (Player) event.getSource().getEntity());
            if (amputated) {
                damage /= 4.0F;
            }
        }

        player.setPlayerHealthData(ph);

        event.setAmount(0);

    }
}
