package com.zivilon.cinder_loe.character;

import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.eventhandler.EventPriority;
import cpw.mods.fml.common.gameevent.TickEvent;
import lotr.common.LOTRLevelData;
import lotr.common.entity.npc.*;
import net.minecraft.entity.Entity;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.living.LivingHurtEvent;

import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.passive.EntityAnimal;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.world.World;

import java.util.*;
import java.util.stream.Collectors;

import com.zivilon.cinder_loe.entity.npc.radagast.FangornAnimal;

public class CharacterEventListener {

    public CharacterEventListener() {
        // Register the event listener
        MinecraftForge.EVENT_BUS.register(this);
        FMLCommonHandler.instance().bus().register(this);
    }

    // Mouth of Sauron statics
    private static final int HIRE_INTERVAL = 600;   // every 30s 600 ticks
    private static final double HIRE_RADIUS = 50.0D;  // 50 blocks
    private static final int MAX_HIRED = 10;

    // tick counter
    private static final Map<UUID, Integer> tickCounters = new HashMap<>();
    //command check
    public static final Set<UUID> hiringEnabled = new HashSet<>();

    //Mouth of Sauron event handler
    @SubscribeEvent
    public void onPlayerTick(TickEvent.PlayerTickEvent event) {
        if (event.phase != TickEvent.Phase.END || event.player.worldObj.isRemote) {
            return;
        }

        EntityPlayerMP player = (EntityPlayerMP) event.player;
        UUID id = player.getUniqueID();

        UUID mosId = CharacterRoleAPI.getCharacterRoleUUID("MouthOfSauron");
        if (mosId == null || !mosId.equals(id)) {
            tickCounters.remove(id);
            hiringEnabled.remove(id);
            return;
        }

        if (!hiringEnabled.contains(id)) {
            tickCounters.remove(id);
            return;
        }

        int count = tickCounters.getOrDefault(id, 0) + 1;
        if (count < HIRE_INTERVAL) {
            tickCounters.put(id, count);
            return;
        }
        tickCounters.put(id, 0);

        tryHireNPCs(player);
    }


    private static void tryHireNPCs(EntityPlayerMP player) {
        World world   = player.worldObj;
        UUID playerId = player.getUniqueID();

        // Search box
        AxisAlignedBB box = AxisAlignedBB.getBoundingBox(
                player.posX - HIRE_RADIUS, player.posY - HIRE_RADIUS, player.posZ - HIRE_RADIUS,
                player.posX + HIRE_RADIUS, player.posY + HIRE_RADIUS, player.posZ + HIRE_RADIUS
        );

        // 1) Grab all NPCs in the box
        List<LOTREntityNPC> allNPCs = world.getEntitiesWithinAABB(LOTREntityNPC.class, box);

        // 2) Figure out which ones this player already has hired
        List<LOTREntityNPC> alreadyHired = new ArrayList<>();
        for (LOTREntityNPC npc : allNPCs) {
            if (npc.hiredNPCInfo != null
                    && playerId.equals(npc.hiredNPCInfo.getHiringPlayerUUID())) {
                alreadyHired.add(npc);
            }
        }
        if (alreadyHired.size() >= MAX_HIRED) {
            return;  // at cap
        }

        // 3) Filter into candidates (correct type & not already hired)
        List<LOTREntityNPC> candidates = new ArrayList<>();
        for (LOTREntityNPC npc : allNPCs) {
            boolean isCorrectType =
                    npc instanceof LOTREntityOrc
                            || npc instanceof LOTREntityWarg
                            || npc instanceof LOTREntityTroll;

            boolean notAlreadyHired =
                    npc.hiredNPCInfo == null
                            || !playerId.equals(npc.hiredNPCInfo.getHiringPlayerUUID());

            if (isCorrectType && notAlreadyHired) {
                candidates.add(npc);
            }
        }
        if (candidates.isEmpty()) {
            return;
        }

        // 4) Shuffle & hire up to remaining slots
        Collections.shuffle(candidates, world.rand);
        int slots = MAX_HIRED - alreadyHired.size();

        // Track which factions already announced this tick
        Set<String> announced = new HashSet<>();

        for (LOTREntityNPC toHire : candidates) {
            if (slots-- <= 0) break;

            // Alignment check
            float align = LOTRLevelData.getData(player)
                    .getAlignment(toHire.getHiringFaction());
            if (align < 500.0F) continue;

            // Hire the NPC via your handler
            MouthOfSauronEntityHandler entry =
                    new MouthOfSauronEntityHandler(toHire, 500f);
            entry.getOrCreateHiredNPC(world)
                    .hiredNPCInfo.hireUnit(
                            player,
                            false,
                            toHire.getHiringFaction(),
                            entry,
                            "",
                            null
                    );

            // Announce once per faction
            String factionName = toHire.getHiringFaction().factionEntityName();
            if (announced.add(factionName)) {
                String msg = EnumChatFormatting.YELLOW
                        + "You have rallied the "
                        + factionName
                        + " to your cause!";
                player.addChatMessage(new ChatComponentText(msg));
            }
        }
    }






    @SubscribeEvent(priority = EventPriority.NORMAL, receiveCanceled = true)
    public void onLivingHurt(LivingHurtEvent event) {
        // Check if the entity being hurt is a character of interest
        EntityLivingBase damagedEntity = event.entityLiving;

        // Check if the source of damage is an entity
        if (event.source.getSourceOfDamage() instanceof EntityLivingBase) {
            // The entity that caused the damage
            EntityLivingBase damagerEntity = (EntityLivingBase) event.source.getSourceOfDamage();

            if (damagedEntity instanceof EntityPlayerMP) {
                EntityPlayerMP player = (EntityPlayerMP)damagedEntity;

                UUID radagast = CharacterRoleAPI.getCharacterRoleUUID("Radagast");
                if (player.getUniqueID().equals(radagast)) {
                    List<EntityLivingBase> entities = findAnimalsAndFangornEntities((EntityLivingBase)player);
                    for (EntityLivingBase entity : entities) {
                        EntityLiving animal = (EntityLiving) entity;
                        animal.setAttackTarget((EntityLivingBase)damagerEntity);
                    }
                }
            }
        }
    }

    public static List<EntityLivingBase> findAnimalsAndFangornEntities(EntityLivingBase centerEntity) {
        World world = centerEntity.worldObj;
        double searchRadius = 32.0D; // Define the search radius

        // Calculate the search area
        AxisAlignedBB searchArea = AxisAlignedBB.getBoundingBox(
                centerEntity.posX - searchRadius, centerEntity.posY - searchRadius, centerEntity.posZ - searchRadius,
                centerEntity.posX + searchRadius, centerEntity.posY + searchRadius, centerEntity.posZ + searchRadius);

        // Retrieve all entities within the search area
        List entitiesWithinAABB = world.getEntitiesWithinAABB(EntityLivingBase.class, searchArea);
        List<EntityLivingBase> foundEntities = new ArrayList<EntityLivingBase>();

        // Manually filter the entities to match your criteria
        for (Object obj : entitiesWithinAABB) {
            if (obj instanceof EntityAnimal || obj instanceof FangornAnimal) { // Adjust for your custom entity
                foundEntities.add((EntityLivingBase) obj);
            }
        }

        return foundEntities;
    }
}
