using System.Threading;

namespace ZB.MOM.WW.CBDD.Core.Compression;

/// <summary>
/// Thread-safe counters for compression/decompression lifecycle events.
/// </summary>
public sealed class CompressionTelemetry
{
    private long _compressionAttempts;
    private long _compressionSuccesses;
    private long _compressionFailures;
    private long _compressionSkippedTooSmall;
    private long _compressionSkippedInsufficientSavings;
    private long _decompressionAttempts;
    private long _decompressionSuccesses;
    private long _decompressionFailures;
    private long _compressionInputBytes;
    private long _compressionOutputBytes;
    private long _decompressionOutputBytes;
    private long _compressedDocumentCount;
    private long _compressionCpuTicks;
    private long _decompressionCpuTicks;
    private long _checksumFailureCount;
    private long _safetyLimitRejectionCount;

    public long CompressionAttempts => Interlocked.Read(ref _compressionAttempts);
    public long CompressionSuccesses => Interlocked.Read(ref _compressionSuccesses);
    public long CompressionFailures => Interlocked.Read(ref _compressionFailures);
    public long CompressionSkippedTooSmall => Interlocked.Read(ref _compressionSkippedTooSmall);
    public long CompressionSkippedInsufficientSavings => Interlocked.Read(ref _compressionSkippedInsufficientSavings);
    public long DecompressionAttempts => Interlocked.Read(ref _decompressionAttempts);
    public long DecompressionSuccesses => Interlocked.Read(ref _decompressionSuccesses);
    public long DecompressionFailures => Interlocked.Read(ref _decompressionFailures);
    public long CompressionInputBytes => Interlocked.Read(ref _compressionInputBytes);
    public long CompressionOutputBytes => Interlocked.Read(ref _compressionOutputBytes);
    public long DecompressionOutputBytes => Interlocked.Read(ref _decompressionOutputBytes);
    public long CompressedDocumentCount => Interlocked.Read(ref _compressedDocumentCount);
    public long CompressionCpuTicks => Interlocked.Read(ref _compressionCpuTicks);
    public long DecompressionCpuTicks => Interlocked.Read(ref _decompressionCpuTicks);
    public long ChecksumFailureCount => Interlocked.Read(ref _checksumFailureCount);
    public long SafetyLimitRejectionCount => Interlocked.Read(ref _safetyLimitRejectionCount);

    public void RecordCompressionAttempt(int inputBytes)
    {
        Interlocked.Increment(ref _compressionAttempts);
        Interlocked.Add(ref _compressionInputBytes, inputBytes);
    }

    public void RecordCompressionSuccess(int outputBytes)
    {
        Interlocked.Increment(ref _compressionSuccesses);
        Interlocked.Increment(ref _compressedDocumentCount);
        Interlocked.Add(ref _compressionOutputBytes, outputBytes);
    }

    public void RecordCompressionFailure() => Interlocked.Increment(ref _compressionFailures);
    public void RecordCompressionSkippedTooSmall() => Interlocked.Increment(ref _compressionSkippedTooSmall);
    public void RecordCompressionSkippedInsufficientSavings() => Interlocked.Increment(ref _compressionSkippedInsufficientSavings);
    public void RecordDecompressionAttempt() => Interlocked.Increment(ref _decompressionAttempts);
    public void RecordCompressionCpuTicks(long ticks) => Interlocked.Add(ref _compressionCpuTicks, ticks);
    public void RecordDecompressionCpuTicks(long ticks) => Interlocked.Add(ref _decompressionCpuTicks, ticks);
    public void RecordChecksumFailure() => Interlocked.Increment(ref _checksumFailureCount);
    public void RecordSafetyLimitRejection() => Interlocked.Increment(ref _safetyLimitRejectionCount);

    public void RecordDecompressionSuccess(int outputBytes)
    {
        Interlocked.Increment(ref _decompressionSuccesses);
        Interlocked.Add(ref _decompressionOutputBytes, outputBytes);
    }

    public void RecordDecompressionFailure() => Interlocked.Increment(ref _decompressionFailures);

    public CompressionStats GetSnapshot()
    {
        return new CompressionStats
        {
            CompressedDocumentCount = CompressedDocumentCount,
            BytesBeforeCompression = CompressionInputBytes,
            BytesAfterCompression = CompressionOutputBytes,
            CompressionCpuTicks = CompressionCpuTicks,
            DecompressionCpuTicks = DecompressionCpuTicks,
            CompressionFailureCount = CompressionFailures,
            ChecksumFailureCount = ChecksumFailureCount,
            SafetyLimitRejectionCount = SafetyLimitRejectionCount
        };
    }
}
