using EonaCat.LogStack.Extensions;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace EonaCat.LogStack.Core;

// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.

/// <summary>
/// Represents a single log event with efficient memory management through pooling.
/// This struct is designed to minimize allocations and support high-throughput logging.
/// </summary>
public struct LogEvent
{
    public long Timestamp { get; set; }
    public LogLevel Level { get; set; }
    public string Category { get; set; }
    public ReadOnlyMemory<char> Message { get; set; }
    public Exception? Exception { get; set; }
    public Dictionary<string, object?> Properties { get; set; }
    public string CustomData { get; set; }
    public int ThreadId { get; set; }
    public ActivityTraceId TraceId { get; set; }
    public ActivitySpanId SpanId { get; set; }

    /// <summary>
    /// Estimated memory size in bytes for backpressure calculations
    /// </summary>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public int EstimateSize()
    {
        // Base overhead
        int size = 64;

        // Message size
        size += Message.Length * 2;

        // Category size
        size += (Category?.Length ?? 0) * 2;

        // Exception size (estimated)
        if (Exception != null)
        {
            size += 512;
        }

        // Properties size
        size += Properties.Count * 32;

        return size;
    }

    /// <summary>
    /// Creates a timestamp value from DateTime
    /// </summary>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static long CreateTimestamp(DateTime dateTime) => dateTime.Ticks;

    /// <summary>
    /// Converts timestamp back to DateTime
    /// </summary>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static DateTime GetDateTime(long timestamp) => new(timestamp);


    public bool HasProperties => Properties != null && Properties.Count > 0;
    public bool HasCustomData => CustomData != null && CustomData.Length > 0;
    public bool HasException => Exception != null;
    public bool HasCategory => Category != null;
}

/// <summary>
/// Builder for creating LogEvent instances with minimal allocations
/// </summary>
public struct LogEventBuilder
{
    private long _timestamp;
    private LogLevel _level;
    private string? _category;
    private ReadOnlyMemory<char> _message;
    private Exception? _exception;
    private Dictionary<string, object>? _properties;
    private int _threadId;
    private ActivityTraceId _traceId;
    private ActivitySpanId _spanId;

    public LogEventBuilder()
    {
        _timestamp = DateTime.UtcNow.Ticks;
        _level = LogLevel.Information;
        _threadId = Environment.CurrentManagedThreadId;

        var activity = Activity.Current;
        _traceId = activity?.TraceId ?? default;
        _spanId = activity?.SpanId ?? default;
    }

    public string? Category => _category;

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public LogEventBuilder WithTimestamp(long timestamp)
    {
        _timestamp = timestamp;
        return this;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public LogEventBuilder WithLevel(LogLevel level)
    {
        _level = level;
        return this;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public LogEventBuilder WithCategory(string category)
    {
        _category = category;
        return this;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public LogEventBuilder WithMessage(ReadOnlyMemory<char> message)
    {
        _message = message;
        return this;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public LogEventBuilder WithMessage(string message)
    {
        _message = message.AsMemory();
        return this;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public LogEventBuilder WithException(Exception? exception)
    {
        _exception = exception;
        return this;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public LogEventBuilder WithProperty(string key, object? value)
    {
        _properties ??= new Dictionary<string, object>(4);
        _properties.TryAdd(key, value);
        return this;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public LogEvent Build()
    {
        return new LogEvent
        {
            Timestamp = _timestamp,
            Level = _level,
            Category = _category ?? string.Empty,
            Message = _message,
            Exception = _exception,
            Properties = _properties ?? new Dictionary<string, object>(),
            ThreadId = _threadId,
            TraceId = _traceId,
            SpanId = _spanId
        };
    }
}