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;

    /// <summary>
    /// Gets the number of attempted compression operations.
    /// </summary>
    public long CompressionAttempts => Interlocked.Read(ref _compressionAttempts);

    /// <summary>
    /// Gets the number of successful compression operations.
    /// </summary>
    public long CompressionSuccesses => Interlocked.Read(ref _compressionSuccesses);

    /// <summary>
    /// Gets the number of failed compression operations.
    /// </summary>
    public long CompressionFailures => Interlocked.Read(ref _compressionFailures);

    /// <summary>
    /// Gets the number of compression attempts skipped because payloads were too small.
    /// </summary>
    public long CompressionSkippedTooSmall => Interlocked.Read(ref _compressionSkippedTooSmall);

    /// <summary>
    /// Gets the number of compression attempts skipped due to insufficient savings.
    /// </summary>
    public long CompressionSkippedInsufficientSavings => Interlocked.Read(ref _compressionSkippedInsufficientSavings);

    /// <summary>
    /// Gets the number of attempted decompression operations.
    /// </summary>
    public long DecompressionAttempts => Interlocked.Read(ref _decompressionAttempts);

    /// <summary>
    /// Gets the number of successful decompression operations.
    /// </summary>
    public long DecompressionSuccesses => Interlocked.Read(ref _decompressionSuccesses);

    /// <summary>
    /// Gets the number of failed decompression operations.
    /// </summary>
    public long DecompressionFailures => Interlocked.Read(ref _decompressionFailures);

    /// <summary>
    /// Gets the total input bytes observed by compression attempts.
    /// </summary>
    public long CompressionInputBytes => Interlocked.Read(ref _compressionInputBytes);

    /// <summary>
    /// Gets the total output bytes produced by successful compression attempts.
    /// </summary>
    public long CompressionOutputBytes => Interlocked.Read(ref _compressionOutputBytes);

    /// <summary>
    /// Gets the total output bytes produced by successful decompression attempts.
    /// </summary>
    public long DecompressionOutputBytes => Interlocked.Read(ref _decompressionOutputBytes);

    /// <summary>
    /// Gets the number of documents stored in compressed form.
    /// </summary>
    public long CompressedDocumentCount => Interlocked.Read(ref _compressedDocumentCount);

    /// <summary>
    /// Gets the total CPU ticks spent on compression.
    /// </summary>
    public long CompressionCpuTicks => Interlocked.Read(ref _compressionCpuTicks);

    /// <summary>
    /// Gets the total CPU ticks spent on decompression.
    /// </summary>
    public long DecompressionCpuTicks => Interlocked.Read(ref _decompressionCpuTicks);

    /// <summary>
    /// Gets the number of checksum validation failures.
    /// </summary>
    public long ChecksumFailureCount => Interlocked.Read(ref _checksumFailureCount);

    /// <summary>
    /// Gets the number of decompression safety-limit rejections.
    /// </summary>
    public long SafetyLimitRejectionCount => Interlocked.Read(ref _safetyLimitRejectionCount);

    /// <summary>
    /// Records a compression attempt and its input byte size.
    /// </summary>
    /// <param name="inputBytes">The number of input bytes provided to compression.</param>
    public void RecordCompressionAttempt(int inputBytes)
    {
        Interlocked.Increment(ref _compressionAttempts);
        Interlocked.Add(ref _compressionInputBytes, inputBytes);
    }

    /// <summary>
    /// Records a successful compression operation.
    /// </summary>
    /// <param name="outputBytes">The number of compressed bytes produced.</param>
    public void RecordCompressionSuccess(int outputBytes)
    {
        Interlocked.Increment(ref _compressionSuccesses);
        Interlocked.Increment(ref _compressedDocumentCount);
        Interlocked.Add(ref _compressionOutputBytes, outputBytes);
    }

    /// <summary>
    /// Records a failed compression operation.
    /// </summary>
    public void RecordCompressionFailure() => Interlocked.Increment(ref _compressionFailures);

    /// <summary>
    /// Records that compression was skipped because the payload was too small.
    /// </summary>
    public void RecordCompressionSkippedTooSmall() => Interlocked.Increment(ref _compressionSkippedTooSmall);

    /// <summary>
    /// Records that compression was skipped due to insufficient expected savings.
    /// </summary>
    public void RecordCompressionSkippedInsufficientSavings() => Interlocked.Increment(ref _compressionSkippedInsufficientSavings);

    /// <summary>
    /// Records a decompression attempt.
    /// </summary>
    public void RecordDecompressionAttempt() => Interlocked.Increment(ref _decompressionAttempts);

    /// <summary>
    /// Adds CPU ticks spent performing compression.
    /// </summary>
    /// <param name="ticks">The CPU ticks to add.</param>
    public void RecordCompressionCpuTicks(long ticks) => Interlocked.Add(ref _compressionCpuTicks, ticks);

    /// <summary>
    /// Adds CPU ticks spent performing decompression.
    /// </summary>
    /// <param name="ticks">The CPU ticks to add.</param>
    public void RecordDecompressionCpuTicks(long ticks) => Interlocked.Add(ref _decompressionCpuTicks, ticks);

    /// <summary>
    /// Records a checksum validation failure.
    /// </summary>
    public void RecordChecksumFailure() => Interlocked.Increment(ref _checksumFailureCount);

    /// <summary>
    /// Records a decompression rejection due to safety limits.
    /// </summary>
    public void RecordSafetyLimitRejection() => Interlocked.Increment(ref _safetyLimitRejectionCount);

    /// <summary>
    /// Records a successful decompression operation.
    /// </summary>
    /// <param name="outputBytes">The number of decompressed bytes produced.</param>
    public void RecordDecompressionSuccess(int outputBytes)
    {
        Interlocked.Increment(ref _decompressionSuccesses);
        Interlocked.Add(ref _decompressionOutputBytes, outputBytes);
    }

    /// <summary>
    /// Records a failed decompression operation.
    /// </summary>
    public void RecordDecompressionFailure() => Interlocked.Increment(ref _decompressionFailures);

    /// <summary>
    /// Returns a point-in-time snapshot of compression telemetry.
    /// </summary>
    /// <returns>The aggregated compression statistics.</returns>
    public CompressionStats GetSnapshot()
    {
        return new CompressionStats
        {
            CompressedDocumentCount = CompressedDocumentCount,
            BytesBeforeCompression = CompressionInputBytes,
            BytesAfterCompression = CompressionOutputBytes,
            CompressionCpuTicks = CompressionCpuTicks,
            DecompressionCpuTicks = DecompressionCpuTicks,
            CompressionFailureCount = CompressionFailures,
            ChecksumFailureCount = ChecksumFailureCount,
            SafetyLimitRejectionCount = SafetyLimitRejectionCount
        };
    }
}
