using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace JebAI
{
    /// <summary>
    /// Loads optional prompt modules from GameData/JebAI/PromptModules.cfg.
    /// The built-in persona remains the baseline; config modules append or replace
    /// selected prompt sections so prompt tuning does not require recompilation.
    /// </summary>
    public sealed class JebAIPromptConfig
    {
        private sealed class InteractionPromptConfig
        {
            public bool ReplaceDefault = false;
            public readonly List<string> Lines = new List<string>();
        }

        private static JebAIPromptConfig _instance;
        public static JebAIPromptConfig Instance => _instance ?? (_instance = Load());

        private readonly List<string> _preludeLines = new List<string>();
        private readonly List<string> _identityLines = new List<string>();
        private readonly List<string> _ruleLines = new List<string>();
        private readonly Dictionary<string, List<string>> _traitLines =
            new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
        private readonly Dictionary<string, List<string>> _kerbalLines =
            new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
        private readonly Dictionary<InteractionType, InteractionPromptConfig> _interactionLines =
            new Dictionary<InteractionType, InteractionPromptConfig>();

        public static void Reload() => _instance = Load();

        public List<string> GetPreludeLines()
        {
            return new List<string>(_preludeLines);
        }

        public List<string> GetIdentityLines(ProtoCrewMember crew)
        {
            var lines = new List<string>(_identityLines);
            if (crew == null) return lines;

            AddMappedLines(lines, _traitLines, crew.trait);
            AddMappedLines(lines, _kerbalLines, crew.name);
            return lines;
        }

        public List<string> GetRuleLines()
        {
            return new List<string>(_ruleLines);
        }

        public List<string> GetInteractionLines(InteractionType type)
        {
            if (!_interactionLines.TryGetValue(type, out InteractionPromptConfig config))
                return new List<string>();

            return new List<string>(config.Lines);
        }

        public bool ShouldReplaceDefaultInteraction(InteractionType type)
        {
            return _interactionLines.TryGetValue(type, out InteractionPromptConfig config)
                && config.ReplaceDefault;
        }

        private static JebAIPromptConfig Load()
        {
            var config = new JebAIPromptConfig();
            string path = Path.Combine(
                KSPUtil.ApplicationRootPath, "GameData", "JebAI", "PromptModules.cfg");

            if (!File.Exists(path))
            {
                Debug.Log("[JebAI] PromptModules.cfg not found - using built-in prompt only.");
                return config;
            }

            ConfigNode root = ConfigNode.Load(path)?.GetNode("JebAI_PromptModules");
            if (root == null)
            {
                Debug.LogWarning("[JebAI] Could not parse PromptModules.cfg.");
                return config;
            }

            foreach (ConfigNode node in root.GetNodes("PRELUDE"))
                config._preludeLines.AddRange(GetLines(node));

            foreach (ConfigNode node in root.GetNodes("IDENTITY"))
                config._identityLines.AddRange(GetLines(node));

            foreach (ConfigNode node in root.GetNodes("RULES"))
                config._ruleLines.AddRange(GetLines(node));

            foreach (ConfigNode node in root.GetNodes("TRAIT"))
            {
                string trait = node.GetValue("trait");
                if (string.IsNullOrWhiteSpace(trait)) continue;
                AddMappedLines(config._traitLines, trait, GetLines(node));
            }

            foreach (ConfigNode node in root.GetNodes("KERBAL"))
            {
                string name = node.GetValue("name");
                if (string.IsNullOrWhiteSpace(name)) continue;
                AddMappedLines(config._kerbalLines, name, GetLines(node));
            }

            foreach (ConfigNode node in root.GetNodes("INTERACTION"))
            {
                string typeText = node.GetValue("type");
                if (string.IsNullOrWhiteSpace(typeText))
                    continue;

                if (!Enum.TryParse(typeText, true, out InteractionType type))
                {
                    Debug.LogWarning($"[JebAI] Unknown prompt interaction type '{typeText}'.");
                    continue;
                }

                if (!config._interactionLines.TryGetValue(type, out InteractionPromptConfig interaction))
                {
                    interaction = new InteractionPromptConfig();
                    config._interactionLines[type] = interaction;
                }

                if (bool.TryParse(node.GetValue("replaceDefault"), out bool replaceDefault)
                    && replaceDefault)
                {
                    interaction.ReplaceDefault = true;
                }

                interaction.Lines.AddRange(GetLines(node));
            }

            Debug.Log("[JebAI] Prompt modules loaded.");
            return config;
        }

        private static List<string> GetLines(ConfigNode node)
        {
            var lines = new List<string>();
            if (node == null) return lines;

            string[] values = node.GetValues("line");
            if (values == null) return lines;

            foreach (string value in values)
            {
                if (string.IsNullOrWhiteSpace(value)) continue;
                lines.Add(value.Trim());
            }

            return lines;
        }

        private static void AddMappedLines(
            Dictionary<string, List<string>> map,
            string                          key,
            List<string>                    lines)
        {
            if (lines == null || lines.Count == 0) return;

            if (!map.TryGetValue(key, out List<string> existing))
            {
                existing = new List<string>();
                map[key] = existing;
            }

            existing.AddRange(lines);
        }

        private static void AddMappedLines(
            List<string>                    target,
            Dictionary<string, List<string>> map,
            string                          key)
        {
            if (string.IsNullOrWhiteSpace(key)) return;
            if (!map.TryGetValue(key, out List<string> lines)) return;

            target.AddRange(lines);
        }
    }
}
