using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace EonaCat.LogStack.PerformanceInsights
{
    /// <summary>
    /// Tracks performance metrics for flows and operations.
    /// Measures latency, throughput, and allocations with minimal overhead.
    /// </summary>
    public sealed class PerformanceTracker
    {
        private long _operationCount;
        private long _totalDurationTicks;
        private long _minDurationTicks = long.MaxValue;
        private long _maxDurationTicks;
        private long _errorCount;
        private long _byteCount;
        private readonly object _lock = new();

        /// <summary>
        /// Gets the operation name
        /// </summary>
        public string Name { get; }

        /// <summary>
        /// Gets total operations recorded
        /// </summary>
        public long OperationCount => _operationCount;

        /// <summary>
        /// Gets total duration in milliseconds
        /// </summary>
        public double TotalDurationMs => _totalDurationTicks * 1000.0 / Stopwatch.Frequency;

        /// <summary>
        /// Gets average duration in milliseconds
        /// </summary>
        public double AverageDurationMs => _operationCount > 0 ? TotalDurationMs / _operationCount : 0;

        /// <summary>
        /// Gets minimum duration in milliseconds
        /// </summary>
        public double MinDurationMs => _minDurationTicks == long.MaxValue ? 0 : _minDurationTicks * 1000.0 / Stopwatch.Frequency;

        /// <summary>
        /// Gets maximum duration in milliseconds
        /// </summary>
        public double MaxDurationMs => _maxDurationTicks * 1000.0 / Stopwatch.Frequency;

        /// <summary>
        /// Gets throughput in operations per second
        /// </summary>
        public double ThroughputOpsPerSec => TotalDurationMs > 0 ? (_operationCount / TotalDurationMs) * 1000 : 0;

        /// <summary>
        /// Gets total bytes processed
        /// </summary>
        public long ByteCount => _byteCount;

        /// <summary>
        /// Gets error count
        /// </summary>
        public long ErrorCount => _errorCount;

        /// <summary>
        /// Gets error rate percentage
        /// </summary>
        public double ErrorRatePercent => _operationCount > 0 ? (_errorCount * 100.0) / _operationCount : 0;

        public PerformanceTracker(string name)
        {
            Name = name ?? throw new ArgumentNullException(nameof(name));
        }

        /// <summary>
        /// Records an operation with its duration
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void RecordOperation(long durationTicks, long byteCount = 0, bool isError = false)
        {
            lock (_lock)
            {
                _operationCount++;
                _totalDurationTicks += durationTicks;
                if (durationTicks < _minDurationTicks) _minDurationTicks = durationTicks;
                if (durationTicks > _maxDurationTicks) _maxDurationTicks = durationTicks;
                if (byteCount > 0) _byteCount += byteCount;
                if (isError) _errorCount++;
            }
        }

        /// <summary>
        /// Resets all metrics
        /// </summary>
        public void Reset()
        {
            lock (_lock)
            {
                _operationCount = 0;
                _totalDurationTicks = 0;
                _minDurationTicks = long.MaxValue;
                _maxDurationTicks = 0;
                _errorCount = 0;
                _byteCount = 0;
            }
        }

        /// <summary>
        /// Gets a snapshot of current metrics
        /// </summary>
        public PerformanceMetrics GetMetrics()
        {
            lock (_lock)
            {
                return new PerformanceMetrics
                {
                    Name = Name,
                    OperationCount = _operationCount,
                    TotalDurationMs = TotalDurationMs,
                    AverageDurationMs = AverageDurationMs,
                    MinDurationMs = MinDurationMs,
                    MaxDurationMs = MaxDurationMs,
                    ThroughputOpsPerSec = ThroughputOpsPerSec,
                    ByteCount = _byteCount,
                    ErrorCount = _errorCount,
                    ErrorRatePercent = ErrorRatePercent,
                    CapturedAt = DateTime.UtcNow
                };
            }
        }
    }

    /// <summary>
    /// Snapshot of performance metrics at a point in time
    /// </summary>
    public sealed class PerformanceMetrics
    {
        public string Name { get; set; }
        public long OperationCount { get; set; }
        public double TotalDurationMs { get; set; }
        public double AverageDurationMs { get; set; }
        public double MinDurationMs { get; set; }
        public double MaxDurationMs { get; set; }
        public double ThroughputOpsPerSec { get; set; }
        public long ByteCount { get; set; }
        public long ErrorCount { get; set; }
        public double ErrorRatePercent { get; set; }
        public DateTime CapturedAt { get; set; }

        /// <summary>
        /// Gets a formatted string representation
        /// </summary>
        public override string ToString()
        {
            return $"{Name} | Ops: {OperationCount} | Avg: {AverageDurationMs:F2}ms | Thrput: {ThroughputOpsPerSec:F2} ops/s | Errors: {ErrorCount} ({ErrorRatePercent:F2}%)";
        }
    }
}
