using System.Collections.Generic;
using UnityEngine;

namespace JebAI
{
    /// <summary>
    /// Emotional states a Kerbal can be in.
    /// Shaped by game events and remembered across interactions within a flight.
    /// </summary>
    public enum Mood
    {
        Calm,
        Excited,
        Scared,
        Proud,
        Anxious,
        Giddy,
        Resigned,
        Awestruck,
    }

    public class MoodState
    {
        public Mood Current = Mood.Calm;
        public float Intensity = 0.5f;
        public string Reason = "";

        public string Describe()
        {
            switch (Current)
            {
                case Mood.Excited:
                    return Intensity > 0.75f
                        ? "buzzing with adrenaline, barely containable"
                        : "in noticeably good spirits";

                case Mood.Scared:
                    return Intensity > 0.75f
                        ? "genuinely frightened, holding it together by a thread"
                        : "a bit rattled and on edge";

                case Mood.Proud:
                    return Intensity > 0.75f
                        ? "swelling with pride, almost insufferably pleased"
                        : "quietly but genuinely satisfied";

                case Mood.Anxious:
                    return Intensity > 0.75f
                        ? "wound tight with worry, watching everything"
                        : "mildly tense, a low hum of concern";

                case Mood.Giddy:
                    return "riding a wild post-danger high - almost manic";

                case Mood.Resigned:
                    return "strangely calm, the kind that comes after too many close calls";

                case Mood.Awestruck:
                    return "struck silent by the sheer scale of what they're seeing";

                default:
                    return "relatively composed, baseline Kerbal";
            }
        }
    }

    public static class KerbalMoodTracker
    {
        private static readonly Dictionary<string, MoodState> _moods =
            new Dictionary<string, MoodState>();

        public static MoodState Get(string kerbalName)
        {
            if (!_moods.TryGetValue(kerbalName, out MoodState mood))
            {
                mood = new MoodState();
                _moods[kerbalName] = mood;
            }
            return mood;
        }

        public static void Set(string kerbalName, Mood mood, float intensity, string reason = "")
        {
            MoodState state = Get(kerbalName);
            state.Current = mood;
            state.Intensity = Mathf.Clamp01(intensity);
            state.Reason = reason;
        }

        public static void ApplyEvent(string kerbalName, GameEvent evt, float courage, float stupidity)
        {
            MoodState state = Get(kerbalName);

            Mood targetMood;
            float targetIntensity;
            string reason;

            switch (evt)
            {
                case GameEvent.Staging:
                    if (courage > 0.6f)
                    {
                        targetMood = Mood.Excited;
                        targetIntensity = 0.6f + stupidity * 0.3f;
                        reason = "stage just fired";
                    }
                    else
                    {
                        targetMood = Mood.Scared;
                        targetIntensity = 0.4f + (1f - courage) * 0.4f;
                        reason = "stage fired - not ready";
                    }
                    break;

                case GameEvent.OrbitAchieved:
                    targetMood = Mood.Proud;
                    targetIntensity = 0.85f;
                    reason = "just achieved orbit";
                    break;

                case GameEvent.AtmosphericEntry:
                    targetMood = courage > 0.5f ? Mood.Excited : Mood.Scared;
                    targetIntensity = 0.7f + (1f - courage) * 0.25f;
                    reason = "entering atmosphere";
                    break;

                case GameEvent.Crash:
                    targetMood = courage > 0.55f ? Mood.Giddy : Mood.Scared;
                    targetIntensity = 1.0f;
                    reason = "just survived a crash";
                    break;

                case GameEvent.Landing:
                    targetMood = Mood.Proud;
                    targetIntensity = 0.75f;
                    reason = "safe landing";
                    break;

                case GameEvent.Splashdown:
                    targetMood = Mood.Proud;
                    targetIntensity = 0.65f;
                    reason = "splashdown";
                    break;

                case GameEvent.LowFuel:
                    targetMood = Mood.Anxious;
                    targetIntensity = 0.75f + (1f - courage) * 0.25f;
                    reason = "fuel critically low";
                    break;

                case GameEvent.EVA:
                    targetMood = courage > 0.4f ? Mood.Excited : Mood.Anxious;
                    targetIntensity = 0.65f;
                    reason = "just stepped outside";
                    break;

                case GameEvent.SphereOfInfluenceChange:
                    targetMood = Mood.Awestruck;
                    targetIntensity = 0.80f;
                    reason = "entered a new sphere of influence";
                    break;

                default:
                    return;
            }

            float blended = state.Intensity * 0.35f + targetIntensity * 0.65f;
            state.Current = targetIntensity >= blended * 0.6f ? targetMood : state.Current;
            state.Intensity = Mathf.Clamp01(blended);
            state.Reason = reason;
        }

        public static void ApplyAmbientContext(string kerbalName, Vessel vessel, float courage, float stupidity)
        {
            if (vessel == null) return;

            Mood targetMood = Mood.Calm;
            float targetIntensity = 0.45f;
            string reason = vessel.GetVesselCrew().Count <= 1
                ? "alone with their thoughts"
                : "settling into the crew rhythm";

            double fuelPercent = GetLiquidFuelPercent(vessel);
            if (fuelPercent >= 0d && fuelPercent < 10d)
            {
                targetMood = Mood.Anxious;
                targetIntensity = 0.72f + (1f - courage) * 0.18f;
                reason = "fuel feels worryingly low";
            }
            else if (vessel.externalTemperature > 1200f)
            {
                targetMood = courage > 0.55f ? Mood.Excited : Mood.Scared;
                targetIntensity = 0.72f;
                reason = "re-entry heat is building outside the hull";
            }
            else if (vessel.geeForce > 4.5f)
            {
                targetMood = courage > 0.6f ? Mood.Excited : Mood.Anxious;
                targetIntensity = 0.65f;
                reason = "under heavy g-load";
            }
            else if (vessel.isEVA)
            {
                targetMood = courage > 0.45f ? Mood.Excited : Mood.Anxious;
                targetIntensity = 0.62f;
                reason = "outside the vessel with nothing but a suit between them and space";
            }
            else
            {
                switch (vessel.situation)
                {
                    case Vessel.Situations.PRELAUNCH:
                        targetMood = courage > 0.55f ? Mood.Excited : Mood.Anxious;
                        targetIntensity = 0.55f;
                        reason = "waiting for launch";
                        break;

                    case Vessel.Situations.FLYING:
                    case Vessel.Situations.SUB_ORBITAL:
                        targetMood = courage > 0.55f ? Mood.Excited : Mood.Anxious;
                        targetIntensity = 0.55f + Mathf.Clamp01((float)vessel.speed / 1800f) * 0.15f;
                        reason = "moving fast through atmosphere";
                        break;

                    case Vessel.Situations.ORBITING:
                        targetMood = Mood.Awestruck;
                        targetIntensity = 0.62f;
                        reason = $"weightless above {vessel.mainBody.displayName}";
                        break;

                    case Vessel.Situations.ESCAPING:
                        targetMood = Mood.Awestruck;
                        targetIntensity = 0.70f;
                        reason = $"slipping away from {vessel.mainBody.displayName}";
                        break;

                    case Vessel.Situations.LANDED:
                        targetMood = Mood.Calm;
                        targetIntensity = 0.42f;
                        reason = $"safely on the surface of {vessel.mainBody.displayName}";
                        break;

                    case Vessel.Situations.SPLASHED:
                        targetMood = Mood.Proud;
                        targetIntensity = 0.48f;
                        reason = "bobbing on the water after a hard mission";
                        break;
                }
            }

            ApplyAmbientBlend(kerbalName, targetMood, targetIntensity, reason);
        }

        public static void DecayAll(float deltaSeconds)
        {
            float decayRate = 0.02f * deltaSeconds;
            foreach (MoodState mood in _moods.Values)
            {
                if (mood.Current == Mood.Calm) continue;
                mood.Intensity -= decayRate;
                if (mood.Intensity <= 0.15f)
                {
                    mood.Current = Mood.Calm;
                    mood.Intensity = 0.5f;
                    mood.Reason = "";
                }
            }
        }

        private static void ApplyAmbientBlend(string kerbalName, Mood targetMood, float targetIntensity, string reason)
        {
            MoodState state = Get(kerbalName);
            float blended = Mathf.Clamp01(state.Intensity * 0.55f + targetIntensity * 0.45f);
            bool keepCurrent = state.Current != Mood.Calm && state.Intensity > targetIntensity + 0.15f;

            if (keepCurrent)
            {
                state.Intensity = Mathf.Clamp01(state.Intensity * 0.96f);
                return;
            }

            state.Current = targetMood;
            state.Intensity = blended;
            state.Reason = reason;
        }

        private static double GetLiquidFuelPercent(Vessel vessel)
        {
            if (vessel?.parts == null) return -1d;

            double amount = 0d;
            double maxAmount = 0d;
            foreach (Part part in vessel.parts)
            {
                foreach (PartResource resource in part.Resources)
                {
                    if (resource.resourceName != "LiquidFuel") continue;
                    amount += resource.amount;
                    maxAmount += resource.maxAmount;
                }
            }

            return maxAmount > 0d ? (amount / maxAmount) * 100d : -1d;
        }
    }
}
