using System.Runtime.CompilerServices;
using AyCode.Core.Enums;
using AyCode.Core.Loggers;

namespace AyCode.Core.Tests.TestModels;

/// <summary>
/// Test logger that captures log messages for assertions and writes to console.
/// Does not require configuration or log writers.
/// </summary>
public class TestLogger : AcLoggerBase
{
    public List<LogEntry> Logs { get; } = [];
    
    public TestLogger() : base(AppType.Server, LogLevel.Detail, "TestLogger")
    {
    }

    public override void Detail(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
    {
        var entry = new LogEntry(LogLevel.Detail, text, categoryName, memberName);
        Logs.Add(entry);
        Console.WriteLine(entry);
    }

    public override void Debug(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
    {
        var entry = new LogEntry(LogLevel.Debug, text, categoryName, memberName);
        Logs.Add(entry);
        Console.WriteLine(entry);
    }

    public override void Info(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
    {
        var entry = new LogEntry(LogLevel.Info, text, categoryName, memberName);
        Logs.Add(entry);
        Console.WriteLine(entry);
    }

    public override void Warning(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
    {
        var entry = new LogEntry(LogLevel.Warning, text, categoryName, memberName);
        Logs.Add(entry);
        Console.WriteLine(entry);
    }

    public override void Suggest(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null)
    {
        var entry = new LogEntry(LogLevel.Suggest, text, categoryName, memberName);
        Logs.Add(entry);
        Console.WriteLine(entry);
    }

    public override void Error(string? text, Exception? ex = null, string? categoryName = null, [CallerMemberName] string? memberName = null)
    {
        var entry = new LogEntry(LogLevel.Error, text, categoryName, memberName, ex);
        Logs.Add(entry);
        Console.WriteLine(entry);
        if (ex != null)
            Console.WriteLine($"  Exception: {ex.Message}");
    }

    public void Clear() => Logs.Clear();

    public bool HasErrorLogs => Logs.Any(l => l.Level == LogLevel.Error);
    public bool HasWarningLogs => Logs.Any(l => l.Level == LogLevel.Warning);
    public IEnumerable<LogEntry> ErrorLogs => Logs.Where(l => l.Level == LogLevel.Error);
    public IEnumerable<LogEntry> WarningLogs => Logs.Where(l => l.Level == LogLevel.Warning);
    
    public IEnumerable<string> GetErrorMessages() => ErrorLogs.Select(l => $"{l.Text} {l.Exception?.Message}");
    public IEnumerable<string> GetAllMessages() => Logs.Select(l => l.ToString());
}

public record LogEntry(
    LogLevel Level, 
    string? Text, 
    string? CategoryName = null, 
    string? MemberName = null, 
    Exception? Exception = null)
{
    public override string ToString() => $"[{Level}] {Text}";
}
