using System.IO;
using UnityEditor;
using UnityEngine;
using LLM.Editor.Data;
using LLM.Editor.Helper;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;

namespace LLM.Editor.Core
{
    /// <summary>
    /// Handles all file I/O for the session cache.
    /// Manages to create new sessions, reading/writing chat logs, and persisting the command queue.
    /// </summary>
    public static class SessionManager
    {
        private static readonly string _sessionCacheRoot;
        private static string _currentSessionId;

        private const string SESSION_ID_KEY = "MCP_CurrentSessionID";
        private const string QUEUE_FILE = "queue.json";
        private const string CHAT_LOG_FILE = "chat_log.json";
        private const string WORKING_CONTEXT_FILE = "working_context.json";
        private const string IDENTIFIER_MAP_FILE = "identifier_map.json";
        private const string LAST_PROMPT_FILE = "last_prompt.txt";

        // Helper class for serializing a list to JSON
        [System.Serializable] private class CommandListWrapper { public List<CommandData> commands; }
        [System.Serializable] private class ChatLogWrapper { public List<ChatEntry> history; }

        static SessionManager()
        {
            _sessionCacheRoot = Path.Combine(Application.persistentDataPath, "LLMCache");
            Directory.CreateDirectory(_sessionCacheRoot);
            _currentSessionId = SessionState.GetString(SESSION_ID_KEY, null);
            Debug.Log($"[SessionManager] Initialized. Current Session: {_currentSessionId}");
        }

        public static string GetCurrentSessionId() => _currentSessionId;

        public static string GetSessionCachePath()
        {
            if (!HasActiveSession()) return null;
            return Path.Combine(_sessionCacheRoot, _currentSessionId);
        }

        public static bool HasActiveSession() => !string.IsNullOrEmpty(_currentSessionId) && Directory.Exists(Path.Combine(_sessionCacheRoot, _currentSessionId));

        public static void StartNewSession()
        {
            _currentSessionId = $"session_{System.DateTime.Now:yyyyMMddHHmmss}";
            SessionState.SetString(SESSION_ID_KEY, _currentSessionId);
            Directory.CreateDirectory(Path.Combine(_sessionCacheRoot, _currentSessionId));
            SaveWorkingContext(new JObject());
            SaveIdentifierMap(new Dictionary<string, PersistentIdentifier>());
            SaveCurrentUserPrompt(string.Empty);
            Debug.Log($"[SessionManager] Started new session: {_currentSessionId}");
        }

        public static void EndSession()
        {
            _currentSessionId = null;
            SessionState.EraseString(SESSION_ID_KEY);
            Debug.Log("[SessionManager] Ended session.");
        }

        public static void SaveCommandQueue(List<CommandData> queue)
        {
            if (!HasActiveSession())
            {
                Debug.LogError("[SessionManager] Cannot save queue, no active session.");
                return;
            }

            var wrapper = new CommandListWrapper { commands = queue };
            var json = wrapper.ToJson();
            var path = Path.Combine(GetSessionCachePath(), QUEUE_FILE);
            File.WriteAllText(path, json);
        }

        public static List<CommandData> LoadCommandQueue()
        {
            if (!HasActiveSession()) return new List<CommandData>();

            var path = Path.Combine(GetSessionCachePath(), QUEUE_FILE);
            if (!File.Exists(path)) return new List<CommandData>();

            var json = File.ReadAllText(path);
            var wrapper = json.FromJson<CommandListWrapper>();
            return wrapper?.commands ?? new List<CommandData>();
        }

        public static void SaveChatHistory(List<ChatEntry> history)
        {
            if (!HasActiveSession()) return;
            var wrapper = new ChatLogWrapper { history = history };
            var json = wrapper.ToJson();
            var path = Path.Combine(GetSessionCachePath(), CHAT_LOG_FILE);
            File.WriteAllText(path, json);
        }

        public static List<ChatEntry> LoadChatHistory()
        {
            if (!HasActiveSession()) return new List<ChatEntry>();
            var path = Path.Combine(GetSessionCachePath(), CHAT_LOG_FILE);
            if (!File.Exists(path)) return new List<ChatEntry>();
            var json = File.ReadAllText(path);
            var wrapper = json.FromJson<ChatLogWrapper>();
            return wrapper?.history ?? new List<ChatEntry>();
        }
        
        public static void SaveWorkingContext(JObject context)
        {
            if (!HasActiveSession()) return;
            var path = Path.Combine(GetSessionCachePath(), WORKING_CONTEXT_FILE);
            File.WriteAllText(path, context.ToString(Formatting.Indented));
        }

        public static JObject LoadWorkingContext()
        {
            if (!HasActiveSession()) return new JObject();
            var path = Path.Combine(GetSessionCachePath(), WORKING_CONTEXT_FILE);
            if (!File.Exists(path)) return new JObject();
            var json = File.ReadAllText(path);
            return JObject.Parse(json);
        }
        
        public static void SaveIdentifierMap(Dictionary<string, PersistentIdentifier> map)
        {
            if (!HasActiveSession()) return;
            var path = Path.Combine(GetSessionCachePath(), IDENTIFIER_MAP_FILE);
            var json = JsonConvert.SerializeObject(map, Formatting.Indented);
            File.WriteAllText(path, json);
        }

        public static Dictionary<string, PersistentIdentifier> LoadIdentifierMap()
        {
            if (!HasActiveSession()) return new Dictionary<string, PersistentIdentifier>();
            var path = Path.Combine(GetSessionCachePath(), IDENTIFIER_MAP_FILE);
            if (!File.Exists(path)) return new Dictionary<string, PersistentIdentifier>();
            var json = File.ReadAllText(path);
            return JsonConvert.DeserializeObject<Dictionary<string, PersistentIdentifier>>(json) ?? new Dictionary<string, PersistentIdentifier>();
        }
        
        public static void SaveCurrentUserPrompt(string prompt)
        {
            if (!HasActiveSession()) return;
            var path = Path.Combine(GetSessionCachePath(), LAST_PROMPT_FILE);
            File.WriteAllText(path, prompt);
        }

        public static string LoadCurrentUserPrompt()
        {
            if (!HasActiveSession()) return string.Empty;
            var path = Path.Combine(GetSessionCachePath(), LAST_PROMPT_FILE);
            return File.Exists(path) ? File.ReadAllText(path) : string.Empty;
        }
    }
}