package com.tiedup.remake.personality;

import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.LivingEntity;

/**
 * Manages the 2 basic needs of an NPC: HUNGER and REST.
 * Needs decay over time and affect mood and behavior.
 *
 * REST replaces the old DIGNITY system:
 * - Decreases during active work (jobs)
 * - Increases when idle, sitting, or sleeping
 * - Affects job efficiency, movement speed, and attack damage
 */
public class NpcNeeds {

    /** Maximum value for any need */
    public static final float MAX_VALUE = 100.0f;

    /** Threshold for "low" state (tired/hungry) */
    public static final float LOW_THRESHOLD = 30.0f;

    /** Threshold for "critical" state (exhausted/starving) */
    public static final float CRITICAL_THRESHOLD = 10.0f;

    /** Threshold for "well rested" bonus */
    public static final float RESTED_THRESHOLD = 70.0f;

    // Current need values (0-100)
    private float hunger = MAX_VALUE;
    private float rest = MAX_VALUE;

    // Previous tick states for transition detection
    private boolean wasHungry = false;
    private boolean wasStarving = false;
    private boolean wasTired = false;
    private boolean wasExhausted = false;

    // Decay/recovery rates per tick (20 ticks = 1 second)
    private static final float HUNGER_DECAY = 0.001f; // ~8.3 min to empty

    // Rest drain during work
    private static final float REST_DRAIN_WORK = 0.002f; // ~8.3 min of work to empty

    // Rest recovery rates (per tick, 20 ticks/sec)
    private static final float REST_RECOVERY_SLEEPING = 0.028f; // ~3 min from 0 to 100 (in bed)
    private static final float REST_RECOVERY_SITTING = 0.01f; // ~8 min from 0 to 100 (in pet bed/home)
    private static final float REST_RECOVERY_IDLE = 0.0025f; // ~33 min from 0 to 100 (standing idle)

    // --- Getters ---

    public float getHunger() {
        return hunger;
    }

    public float getRest() {
        return rest;
    }

    // --- State checks ---

    public boolean isHungry() {
        return hunger < LOW_THRESHOLD;
    }

    public boolean isStarving() {
        return hunger < CRITICAL_THRESHOLD;
    }

    public boolean isTired() {
        return rest < LOW_THRESHOLD;
    }

    public boolean isExhausted() {
        return rest < CRITICAL_THRESHOLD;
    }

    public boolean isRested() {
        return rest >= RESTED_THRESHOLD;
    }

    // --- Modification ---

    public void setHunger(float value) {
        this.hunger = clamp(value);
    }

    public void setRest(float value) {
        this.rest = clamp(value);
    }

    public void modifyHunger(float delta) {
        this.hunger = clamp(this.hunger + delta);
    }

    public void modifyRest(float delta) {
        this.rest = clamp(this.rest + delta);
    }

    /**
     * Drain rest during active work.
     * @param workIntensity Multiplier for drain rate (1.0 = normal)
     */
    public void drainFromWork(float workIntensity) {
        this.rest = clamp(this.rest - REST_DRAIN_WORK * workIntensity);
    }

    /**
     * Recover rest while resting.
     * @param restType Type of rest (SLEEPING, SITTING, or IDLE)
     */
    public void recoverRest(RestType restType) {
        float recovery = switch (restType) {
            case SLEEPING -> REST_RECOVERY_SLEEPING;
            case SITTING -> REST_RECOVERY_SITTING;
            case IDLE -> REST_RECOVERY_IDLE;
        };
        this.rest = clamp(this.rest + recovery);
    }

    /**
     * Feed the NPC.
     *
     * @param nutritionValue How much hunger to restore (1-20 typically)
     */
    public void feed(float nutritionValue) {
        modifyHunger(nutritionValue * 5); // Food items restore 5x their value
    }

    // --- Efficiency Modifiers ---

    /**
     * Get job efficiency modifier based on rest level.
     * @return 0.4 (exhausted) to 1.0 (normal/rested)
     */
    public float getEfficiencyModifier() {
        if (isExhausted()) return 0.4f;
        if (isTired()) return 0.7f;
        return 1.0f;
    }

    /**
     * Get movement speed modifier based on rest level.
     * @return 0.6 (exhausted) to 1.0 (normal/rested)
     */
    public float getSpeedModifier() {
        if (isExhausted()) return 0.6f;
        if (isTired()) return 0.8f;
        return 1.0f;
    }

    /**
     * Get attack damage modifier based on rest level.
     * @return 0.7 (exhausted) to 1.0 (normal/rested)
     */
    public float getDamageModifier() {
        if (isExhausted()) return 0.7f;
        if (isTired()) return 0.9f;
        return 1.0f;
    }

    // --- Tick update ---

    /** Shared empty transitions instance to avoid allocation */
    private static final NeedTransitions EMPTY_TRANSITIONS =
        new NeedTransitions();

    /**
     * Update needs based on current state. Called every tick.
     *
     * @param entity The entity to check state from
     * @param personality The personality (unused, kept for API compat)
     * @param isWorking Whether the NPC is currently doing an active job
     * @return NeedTransitions containing any threshold crossings this tick
     */
    public NeedTransitions tick(
        LivingEntity entity,
        PersonalityType personality,
        boolean isWorking,
        RestType restType
    ) {
        // Hunger always decays
        hunger = clamp(hunger - HUNGER_DECAY);

        // Rest logic: drain when working, recover based on rest type
        if (isWorking) {
            rest = clamp(rest - REST_DRAIN_WORK);
        } else {
            // Recovery rate depends on rest type (BED=SLEEPING, PET_BED=SITTING, else=IDLE)
            recoverRest(restType);
        }

        // Detect transitions (threshold crossings)
        boolean transitionOccurred = false;
        NeedTransitions transitions = null;

        // Hunger transitions
        if (isHungry() && !wasHungry) {
            if (transitions == null) transitions = new NeedTransitions();
            transitions.becameHungry = true;
            transitionOccurred = true;
        }
        if (isStarving() && !wasStarving) {
            if (transitions == null) transitions = new NeedTransitions();
            transitions.becameStarving = true;
            transitionOccurred = true;
        }

        // Rest transitions
        if (isTired() && !wasTired) {
            if (transitions == null) transitions = new NeedTransitions();
            transitions.becameTired = true;
            transitionOccurred = true;
        }
        if (isExhausted() && !wasExhausted) {
            if (transitions == null) transitions = new NeedTransitions();
            transitions.becameExhausted = true;
            transitionOccurred = true;
        }

        // Update previous states for next tick
        wasHungry = isHungry();
        wasStarving = isStarving();
        wasTired = isTired();
        wasExhausted = isExhausted();

        return transitionOccurred ? transitions : EMPTY_TRANSITIONS;
    }

    /**
     * Calculate overall mood impact from needs.
     *
     * @return Mood modifier (-40 to +5)
     */
    public float getMoodImpact() {
        float impact = 0;

        // Hunger impact
        if (isStarving()) impact -= 20;
        else if (isHungry()) impact -= 10;
        else if (hunger > 80) impact += 5;

        // Rest impact
        if (isExhausted()) impact -= 20;
        else if (isTired()) impact -= 10;
        else if (isRested()) impact += 5;

        return impact;
    }

    /**
     * Get the most critical need (lowest value).
     *
     * @return The need type that's lowest
     */
    public NeedType getMostCriticalNeed() {
        if (rest < hunger) {
            return NeedType.REST;
        }
        return NeedType.HUNGER;
    }

    public enum NeedType {
        HUNGER,
        REST,
    }

    public enum RestType {
        SLEEPING, // In bed - fastest recovery
        SITTING, // In pet bed/home - medium recovery
        IDLE, // Standing idle - slow recovery
    }

    /**
     * Holds information about need state transitions that occurred this tick.
     * Used to trigger dialogues when needs cross thresholds.
     */
    public static class NeedTransitions {

        public boolean becameHungry = false;
        public boolean becameStarving = false;
        public boolean becameTired = false;
        public boolean becameExhausted = false;

        /** Returns true if any transition occurred */
        public boolean hasAny() {
            return (
                becameHungry || becameStarving || becameTired || becameExhausted
            );
        }
    }

    // --- NBT Persistence ---

    public CompoundTag save() {
        CompoundTag tag = new CompoundTag();
        tag.putFloat("Hunger", hunger);
        tag.putFloat("Rest", rest);
        return tag;
    }

    public static NpcNeeds load(CompoundTag tag) {
        NpcNeeds needs = new NpcNeeds();
        if (tag.contains("Hunger")) needs.hunger = clamp(
            tag.getFloat("Hunger")
        );
        // Support both new "Rest" and legacy "Dignity" keys
        if (tag.contains("Rest")) {
            needs.rest = clamp(tag.getFloat("Rest"));
        } else if (tag.contains("Dignity")) {
            needs.rest = clamp(tag.getFloat("Dignity"));
        }
        return needs;
    }

    // --- Utility ---

    private static float clamp(float value) {
        return Math.max(0, Math.min(MAX_VALUE, value));
    }
}
