using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace JebAI
{
    /// <summary>
    /// PartModule that attaches to crewed command parts and EVA Kerbals at runtime.
    /// Adds a right-click menu group with all player-initiated Kerbal interactions.
    ///
    /// Unlike the initial prototype, this module does not assume "first crew in
    /// the pod." The player explicitly targets a named Kerbal seated in this part,
    /// then every action is routed to that crew member.
    ///
    ///   • Poke           — one impulsive sentence
    ///   • Speak          — up to 3 sentences, more deliberate
    ///   • Chat           — opens the full per-Kerbal chat window
    ///   • Ask Fears      — vulnerability prompt; surfaces what scares them
    ///   • Ask Dreams     — what they're actually flying toward
    ///   • Reflect        — how they feel about this mission so far
    ///   • Ask Crewmate   — their honest opinion of another crew member
    ///
    /// Only visible in flight, not in the editor.
    /// </summary>
    public class KerbalNPCModule : PartModule
    {
        private const string Group        = "JebAI";
        private const string GroupDisplay = "JebAI - Crew";

        private int    _selectedCrewIndex = 0;
        private string _selectedCrewName  = null;

        [KSPField(guiActive = true, guiActiveEditor = false, guiName = "Target Kerbal")]
        public string SelectedKerbal = "None";

        // ── Right-click events ─────────────────────────────────────────────────

        [KSPEvent(
            guiActive = true, guiActiveEditor = false, guiActiveUnfocused = true, unfocusedRange = 4f,
            guiName = "Switch Target Kerbal", groupName = Group, groupDisplayName = GroupDisplay)]
        public void CycleTargetKerbal()
        {
            List<ProtoCrewMember> crew = GetCrewList();
            if (crew.Count <= 1) return;

            ResolveSelectedCrew(showEmptyMessage: false);
            _selectedCrewIndex = (_selectedCrewIndex + 1) % crew.Count;
            _selectedCrewName = crew[_selectedCrewIndex].name;

            ScreenMessages.PostScreenMessage(
                $"[JebAI] Targeting {_selectedCrewName}.",
                2.5f,
                ScreenMessageStyle.UPPER_CENTER);
        }

        [KSPEvent(
            guiActive = true, guiActiveEditor = false, guiActiveUnfocused = true, unfocusedRange = 4f,
            guiName = "Poke Kerbal", groupName = Group, groupDisplayName = GroupDisplay)]
        public void PokeKerbal()
        {
            ProtoCrewMember kerbal = ResolveSelectedCrew();
            if (kerbal == null) return;
            JebAI.Instance?.TriggerPoke(kerbal, part);
        }

        [KSPEvent(
            guiActive = true, guiActiveEditor = false, guiActiveUnfocused = true, unfocusedRange = 4f,
            guiName = "Ask Kerbal to Speak", groupName = Group, groupDisplayName = GroupDisplay)]
        public void SpeakKerbal()
        {
            ProtoCrewMember kerbal = ResolveSelectedCrew();
            if (kerbal == null) return;
            JebAI.Instance?.TriggerSpeak(kerbal, part);
        }

        [KSPEvent(
            guiActive = true, guiActiveEditor = false, guiActiveUnfocused = true, unfocusedRange = 4f,
            guiName = "Chat with Kerbal", groupName = Group, groupDisplayName = GroupDisplay)]
        public void OpenChat()
        {
            ProtoCrewMember kerbal = ResolveSelectedCrew();
            if (kerbal == null) return;
            JebAI.Instance?.OpenChat(kerbal, part);
        }

        [KSPEvent(
            guiActive = true, guiActiveEditor = false, guiActiveUnfocused = true, unfocusedRange = 4f,
            guiName = "Ask About Fears", groupName = Group, groupDisplayName = GroupDisplay)]
        public void AskFears()
        {
            ProtoCrewMember kerbal = ResolveSelectedCrew();
            if (kerbal == null) return;
            JebAI.Instance?.TriggerSpecial(kerbal, InteractionType.AskFears, part);
        }

        [KSPEvent(
            guiActive = true, guiActiveEditor = false, guiActiveUnfocused = true, unfocusedRange = 4f,
            guiName = "Ask About Dreams", groupName = Group, groupDisplayName = GroupDisplay)]
        public void AskDreams()
        {
            ProtoCrewMember kerbal = ResolveSelectedCrew();
            if (kerbal == null) return;
            JebAI.Instance?.TriggerSpecial(kerbal, InteractionType.AskDreams, part);
        }

        [KSPEvent(
            guiActive = true, guiActiveEditor = false, guiActiveUnfocused = true, unfocusedRange = 4f,
            guiName = "Ask to Reflect on Mission", groupName = Group, groupDisplayName = GroupDisplay)]
        public void AskReflect()
        {
            ProtoCrewMember kerbal = ResolveSelectedCrew();
            if (kerbal == null) return;
            JebAI.Instance?.TriggerSpecial(kerbal, InteractionType.AskMission, part);
        }

        [KSPEvent(
            guiActive = true, guiActiveEditor = false, guiActiveUnfocused = true, unfocusedRange = 4f,
            guiName = "Ask About Crewmate", groupName = Group, groupDisplayName = GroupDisplay)]
        public void AskAboutCrewmate()
        {
            ProtoCrewMember kerbal = ResolveSelectedCrew();
            if (kerbal == null) return;

            // Find a different crew member on the vessel to ask about
            Vessel vessel = part?.vessel ?? FlightGlobals.ActiveVessel;
            if (vessel == null) return;

            List<ProtoCrewMember> others = vessel.GetVesselCrew()
                                                 .Where(c => c.name != kerbal.name)
                                                 .ToList();

            if (others.Count == 0)
            {
                ScreenMessages.PostScreenMessage(
                    $"{kerbal.name} is flying solo — no crewmates to ask about.",
                    3f, ScreenMessageStyle.UPPER_CENTER);
                return;
            }

            // Pick a random crewmate to ask about (cycling keeps it interesting)
            var target = others[Random.Range(0, others.Count)];
            JebAI.Instance?.TriggerAskAboutCrewmate(kerbal, target.name, part);
        }

        // ── OnUpdate — labels and visibility ──────────────────────────────────

        public override void OnUpdate()
        {
            List<ProtoCrewMember> crew = GetCrewList();
            bool hasCrew = crew.Count > 0;
            ProtoCrewMember selected = ResolveSelectedCrew(showEmptyMessage: false);
            string name = selected?.name ?? "Kerbal";

            SelectedKerbal = hasCrew
                ? crew.Count > 1 ? $"{name} ({_selectedCrewIndex + 1}/{crew.Count})" : name
                : "None";

            Fields["SelectedKerbal"].guiActive = crew.Count > 1;
            Events["CycleTargetKerbal"].active = crew.Count > 1;
            Events["CycleTargetKerbal"].guiName = crew.Count > 1
                ? $"Switch Target Kerbal ({_selectedCrewIndex + 1}/{crew.Count})"
                : "Switch Target Kerbal";

            Events["PokeKerbal"].guiName  = hasCrew ? $"Poke {name}" : "No Kerbal available";
            Events["SpeakKerbal"].guiName = hasCrew ? $"Ask {name} to Speak" : "No Kerbal available";
            Events["OpenChat"].guiName    = hasCrew ? $"Chat with {name}" : "No Kerbal available";
            Events["AskFears"].guiName    = hasCrew ? $"Ask {name}: What Scares You?" : "No Kerbal available";
            Events["AskDreams"].guiName   = hasCrew ? $"Ask {name}: What Are You After?" : "No Kerbal available";
            Events["AskReflect"].guiName  = hasCrew ? $"Ask {name} to Reflect" : "No Kerbal available";
            Events["AskAboutCrewmate"].guiName = hasCrew ? $"Ask {name} About a Crewmate" : "No Kerbal available";

            foreach (BaseEvent evt in Events)
            {
                if (evt.name == "CycleTargetKerbal") continue;
                evt.active = hasCrew;
            }
        }

        // ── Helpers ────────────────────────────────────────────────────────────

        private List<ProtoCrewMember> GetCrewList()
        {
            if (part?.vessel != null && part.vessel.isEVA)
                return part.vessel.GetVesselCrew() ?? new List<ProtoCrewMember>();

            return part?.protoModuleCrew ?? new List<ProtoCrewMember>();
        }

        private ProtoCrewMember ResolveSelectedCrew(bool showEmptyMessage = true)
        {
            List<ProtoCrewMember> crew = GetCrewList();
            if (crew.Count == 0)
            {
                _selectedCrewIndex = 0;
                _selectedCrewName = null;

                if (showEmptyMessage)
                {
                    ScreenMessages.PostScreenMessage(
                        "No Kerbal is seated in this part.",
                        3f,
                        ScreenMessageStyle.UPPER_CENTER);
                }

                return null;
            }

            if (!string.IsNullOrEmpty(_selectedCrewName))
            {
                for (int i = 0; i < crew.Count; i++)
                {
                    if (crew[i].name != _selectedCrewName) continue;
                    _selectedCrewIndex = i;
                    return crew[i];
                }
            }

            if (_selectedCrewIndex < 0 || _selectedCrewIndex >= crew.Count)
                _selectedCrewIndex = 0;

            ProtoCrewMember selected = crew[_selectedCrewIndex];
            _selectedCrewName = selected.name;
            return selected;
        }
    }
}
