//! Message compression utilities.

use crate::runtime::{Result, RobomotionError};
use flate2::read::GzDecoder;
use flate2::write::GzEncoder;
use flate2::Compression;
use std::io::{Read, Write};

/// Whether compression is enabled (configurable via properties).
static COMPRESSION_ENABLED: std::sync::atomic::AtomicBool =
    std::sync::atomic::AtomicBool::new(true);

/// Enable or disable compression.
pub fn set_compression_enabled(enabled: bool) {
    COMPRESSION_ENABLED.store(enabled, std::sync::atomic::Ordering::SeqCst);
}

/// Check if compression is enabled.
pub fn is_compression_enabled() -> bool {
    COMPRESSION_ENABLED.load(std::sync::atomic::Ordering::SeqCst)
}

/// Compress data using gzip.
pub fn compress(data: &[u8]) -> Result<Vec<u8>> {
    if !is_compression_enabled() {
        return Ok(data.to_vec());
    }

    let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
    encoder
        .write_all(data)
        .map_err(|e| RobomotionError::Compression(e.to_string()))?;
    encoder
        .finish()
        .map_err(|e| RobomotionError::Compression(e.to_string()))
}

/// Decompress gzip data.
pub fn decompress(data: &[u8]) -> Result<Vec<u8>> {
    if !is_compression_enabled() {
        return Ok(data.to_vec());
    }

    let mut decoder = GzDecoder::new(data);
    let mut decompressed = Vec::new();
    decoder
        .read_to_end(&mut decompressed)
        .map_err(|e| RobomotionError::Compression(e.to_string()))?;
    Ok(decompressed)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_compress_decompress() {
        let original = b"Hello, World! This is a test message.";
        let compressed = compress(original).unwrap();
        let decompressed = decompress(&compressed).unwrap();
        assert_eq!(original.to_vec(), decompressed);
    }

    #[test]
    fn test_compression_disabled() {
        set_compression_enabled(false);
        let original = b"Hello, World!";
        let result = compress(original).unwrap();
        assert_eq!(original.to_vec(), result);
        set_compression_enabled(true);
    }
}
