package com.tiedup.remake.entities.ai.personality;

import com.tiedup.remake.entities.EntityDamsel;
import com.tiedup.remake.personality.NpcNeeds;
import com.tiedup.remake.personality.PersonalityState;
import java.util.EnumSet;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.ItemStack;

/**
 * AI Goal: NPC automatically eats food from their inventory when hungry.
 *
 * <p>Triggers when hunger drops below 30 (hungry) or 10 (starving).
 * Searches inventory for edible items and consumes them.
 *
 * <p>Priority: Should run at priority 2 to allow interruption of lower goals
 * but not override critical command goals.
 */
public class NpcAutoEatGoal extends Goal {

    private final EntityDamsel npc;

    /** Ticks between inventory scans when not eating */
    private static final int SCAN_INTERVAL = 40;

    /** Ticks to "eat" the food (animation time) */
    private static final int EAT_DURATION = 32;

    /** Hunger threshold to start seeking food */
    private static final float HUNGER_THRESHOLD = 30.0f;

    /** Critical hunger - higher priority */
    private static final float CRITICAL_THRESHOLD = 10.0f;

    private enum EatPhase {
        IDLE,
        SEARCHING,
        EATING,
    }

    private EatPhase phase = EatPhase.IDLE;
    private int scanTimer = 0;
    private int eatTimer = 0;
    private int foodSlot = -1;
    private ItemStack foodToEat = ItemStack.EMPTY;

    public NpcAutoEatGoal(EntityDamsel npc) {
        this.npc = npc;
        // Don't set MOVE flag - eating doesn't require movement
        this.setFlags(EnumSet.noneOf(Goal.Flag.class));
    }

    @Override
    public boolean canUse() {
        PersonalityState state = npc.getPersonalityState();
        if (state == null) return false;

        NpcNeeds needs = state.getNeeds();

        // Check if hungry
        if (needs.getHunger() >= HUNGER_THRESHOLD) {
            return false;
        }

        // Don't interrupt if already doing a high-priority command
        // (but allow eating during idle/patrol/etc)
        return true;
    }

    @Override
    public boolean canContinueToUse() {
        PersonalityState state = npc.getPersonalityState();
        if (state == null) return false;

        // Stop if no longer hungry (fed enough)
        if (state.getNeeds().getHunger() >= 80.0f) {
            return false;
        }

        // Continue if still eating or searching
        return (
            phase != EatPhase.IDLE ||
            state.getNeeds().getHunger() < HUNGER_THRESHOLD
        );
    }

    @Override
    public void start() {
        this.phase = EatPhase.SEARCHING;
        this.scanTimer = 0;
        this.eatTimer = 0;
        this.foodSlot = -1;
        this.foodToEat = ItemStack.EMPTY;
    }

    @Override
    public void stop() {
        this.phase = EatPhase.IDLE;
        this.foodSlot = -1;
        this.foodToEat = ItemStack.EMPTY;
    }

    @Override
    public boolean requiresUpdateEveryTick() {
        return true;
    }

    @Override
    public void tick() {
        switch (phase) {
            case SEARCHING -> tickSearching();
            case EATING -> tickEating();
            case IDLE -> {
            } // Do nothing
        }
    }

    private void tickSearching() {
        if (--scanTimer > 0) return;
        scanTimer = SCAN_INTERVAL;

        // Search inventory for food
        var inventory = npc.getNpcInventory();
        int bestSlot = -1;
        int bestNutrition = 0;

        for (int i = 0; i < npc.getNpcInventorySize(); i++) {
            ItemStack stack = inventory.get(i);
            if (stack.isEmpty()) continue;

            FoodProperties food = stack.getItem().getFoodProperties();
            if (food != null && food.getNutrition() > bestNutrition) {
                bestSlot = i;
                bestNutrition = food.getNutrition();
            }
        }

        if (bestSlot >= 0) {
            // Found food - start eating
            this.foodSlot = bestSlot;
            this.foodToEat = inventory.get(bestSlot);
            this.phase = EatPhase.EATING;
            this.eatTimer = EAT_DURATION;

            // Play eating sound start
            npc
                .level()
                .playSound(
                    null,
                    npc.blockPosition(),
                    SoundEvents.GENERIC_EAT,
                    SoundSource.NEUTRAL,
                    0.5f,
                    1.0f + (npc.getRandom().nextFloat() - 0.5f) * 0.2f
                );
        } else {
            // No food found - go idle (will retry on next canUse check)
            this.phase = EatPhase.IDLE;
        }
    }

    private void tickEating() {
        if (--eatTimer > 0) {
            // Still eating - play occasional eating particles/sounds
            if (eatTimer % 8 == 0) {
                // Eating particles
                npc
                    .level()
                    .playSound(
                        null,
                        npc.blockPosition(),
                        SoundEvents.GENERIC_EAT,
                        SoundSource.NEUTRAL,
                        0.3f,
                        1.0f + (npc.getRandom().nextFloat() - 0.5f) * 0.4f
                    );
            }
            return;
        }

        // Finished eating - consume food and restore hunger
        if (foodSlot >= 0 && !foodToEat.isEmpty()) {
            var inventory = npc.getNpcInventory();
            ItemStack currentStack = inventory.get(foodSlot);

            // Verify food is still there (in case inventory changed)
            if (
                !currentStack.isEmpty() &&
                ItemStack.isSameItem(currentStack, foodToEat)
            ) {
                FoodProperties food = currentStack
                    .getItem()
                    .getFoodProperties();

                if (food != null) {
                    // Consume one food item
                    currentStack.shrink(1);

                    // Feed the NPC
                    PersonalityState state = npc.getPersonalityState();
                    if (state != null) {
                        // feed() multiplies by 5, so nutrition 6 = 30 hunger restored
                        state.getNeeds().feed(food.getNutrition());

                        // Slight mood boost from eating
                        state.modifyMood(2);
                    }

                    // Burp sound on completion
                    npc
                        .level()
                        .playSound(
                            null,
                            npc.blockPosition(),
                            SoundEvents.PLAYER_BURP,
                            SoundSource.NEUTRAL,
                            0.5f,
                            1.0f
                        );
                }
            }
        }

        // Reset and check if still hungry
        this.foodSlot = -1;
        this.foodToEat = ItemStack.EMPTY;

        PersonalityState state = npc.getPersonalityState();
        if (state != null && state.getNeeds().getHunger() < HUNGER_THRESHOLD) {
            // Still hungry - search for more food
            this.phase = EatPhase.SEARCHING;
            this.scanTimer = 10; // Quick re-scan
        } else {
            // Satisfied
            this.phase = EatPhase.IDLE;
        }
    }

    /**
     * Get the priority adjustment based on hunger level.
     * More hungry = higher effective priority.
     *
     * @return Priority modifier (lower = more urgent)
     */
    public int getAdjustedPriority() {
        PersonalityState state = npc.getPersonalityState();
        if (state == null) return 2;

        float hunger = state.getNeeds().getHunger();
        if (hunger < CRITICAL_THRESHOLD) {
            return 1; // Critical - very high priority
        }
        return 2; // Normal hungry priority
    }
}
