using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;

namespace VibeCopilot.Editor
{
    // O eroare de compilare citita din consola Unity.
    public struct ConsoleError
    {
        public string Message;   // textul erorii (ex: "error CS1002: ; expected")
        public string File;      // calea relativa (ex: "Assets/.../Player.cs")
        public int Line;
        public int Column;
        public string Code;      // codul erorii (ex: "CS1002")
    }

    // Citeste mesajele REALE din consola Unity. Foloseste API-ul intern al Unity
    // prin "reflection", invelit in try/catch ca sa nu crape daca Unity se schimba.
    public static class VibeConsole
    {
        public static List<string> GetAllMessages()
        {
            var result = new List<string>();
            try
            {
                Assembly editorAsm = typeof(UnityEditor.Editor).Assembly;
                Type logEntries = editorAsm.GetType("UnityEditor.LogEntries");
                Type logEntry = editorAsm.GetType("UnityEditor.LogEntry");
                if (logEntries == null || logEntry == null) return result;

                const BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
                MethodInfo start = logEntries.GetMethod("StartGettingEntries", flags);
                MethodInfo end = logEntries.GetMethod("EndGettingEntries", flags);
                MethodInfo getEntry = logEntries.GetMethod("GetEntryInternal", flags);
                MethodInfo getCount = logEntries.GetMethod("GetCount", flags);
                if (start == null || end == null || getEntry == null) return result;

                FieldInfo msgField = logEntry.GetField("message") ?? logEntry.GetField("condition");
                if (msgField == null) return result;

                object startResult = start.Invoke(null, null);
                int count = startResult is int ? (int)startResult
                          : (getCount != null ? (int)getCount.Invoke(null, null) : 0);
                try
                {
                    object entry = Activator.CreateInstance(logEntry);
                    for (int i = 0; i < count; i++)
                    {
                        getEntry.Invoke(null, new object[] { i, entry });
                        string m = msgField.GetValue(entry) as string;
                        if (!string.IsNullOrEmpty(m)) result.Add(m);
                    }
                }
                finally
                {
                    end.Invoke(null, null);
                }
            }
            catch
            {
                // Daca API-ul intern s-a schimbat, returnam ce avem (gol) fara sa crapam.
            }
            return result;
        }

        // Gaseste cea mai recenta eroare de compilare C# (cele care contin "error CS").
        public static bool TryGetLastCompileError(out ConsoleError err)
        {
            err = default;
            List<string> messages = GetAllMessages();
            for (int i = messages.Count - 1; i >= 0; i--)
            {
                if (TryParse(messages[i], out err)) return true;
            }
            return false;
        }

        // Parseaza un mesaj de forma: Assets/.../Player.cs(12,9): error CS1002: ; expected
        private static bool TryParse(string message, out ConsoleError err)
        {
            err = default;
            if (string.IsNullOrEmpty(message)) return false;

            int errIdx = message.IndexOf(": error CS", StringComparison.Ordinal);
            if (errIdx < 0) return false;

            // Partea din fata: "Assets/.../Player.cs(12,9)"
            string head = message.Substring(0, errIdx);
            int paren = head.LastIndexOf('(');
            if (paren > 0 && head.EndsWith(")"))
            {
                err.File = head.Substring(0, paren);
                string nums = head.Substring(paren + 1, head.Length - paren - 2); // "12,9"
                string[] parts = nums.Split(',');
                if (parts.Length > 0) int.TryParse(parts[0], out err.Line);
                if (parts.Length > 1) int.TryParse(parts[1], out err.Column);
            }

            // Partea de dupa: "error CS1002: ; expected"
            string tail = message.Substring(errIdx + 2);
            int newLine = tail.IndexOf('\n');
            if (newLine >= 0) tail = tail.Substring(0, newLine);
            err.Message = tail.Trim();

            int csIdx = tail.IndexOf("CS", StringComparison.Ordinal);
            if (csIdx >= 0)
            {
                int stop = tail.IndexOfAny(new[] { ':', ' ' }, csIdx);
                err.Code = stop > csIdx ? tail.Substring(csIdx, stop - csIdx) : tail.Substring(csIdx);
            }
            return true;
        }
    }
}
