//! Default quantization and zero-bias tables.
//!
//! These tables are exposed for users who want to customize encoding by
//! modifying the defaults rather than starting from scratch.
//!
//! # Quantization Tables
//!
//! The base quantization matrices are 192 f32 values organized as:
//! - `[0..64]`: Y (luma) component
//! - `[64..128]`: Cb (blue chroma) component
//! - `[128..192]`: Cr (red chroma) component
//!
//! Each 64-element block is in row-major order (NOT zigzag).
//!
//! # Zero-Bias Tables
//!
//! Zero-bias controls coefficient rounding during quantization:
//! - `ZERO_BIAS_MUL_*`: Multiplier tables (higher = more aggressive zeroing)
//! - `ZERO_BIAS_OFFSET_*`: Offset tables
//!
//! The encoder blends between HQ and LQ tables based on quality:
//! - Quality >= 88 (distance <= 1.0): Uses HQ tables
//! - Quality <= 73 (distance >= 3.0): Uses LQ tables
//! - In between: Linear blend
//!
//! # Example
//!
//! ```ignore
//! use jpegli::encoder::{EncoderConfig, QuantTableConfig, ChromaSubsampling};
//! use jpegli::encoder::tables;
//!
//! // Start with defaults and modify
//! let mut luma = [0.0f32; 64];
//! let mut cb = [0.0f32; 64];
//! let mut cr = [0.0f32; 64];
//!
//! // Copy from defaults
//! luma.copy_from_slice(&tables::BASE_QUANT_YCBCR[0..64]);
//! cb.copy_from_slice(&tables::BASE_QUANT_YCBCR[64..128]);
//! cr.copy_from_slice(&tables::BASE_QUANT_YCBCR[128..192]);
//!
//! // Modify: reduce DC quantization for sharper edges
//! luma[0] *= 0.5;
//! cb[0] *= 0.5;
//! cr[0] *= 0.5;
//!
//! let config = EncoderConfig::new(85, ChromaSubsampling::None)
//!     .quant_tables(QuantTableConfig::CustomBase { luma, cb, cr });
//! ```

// Re-export base quantization matrices
pub use crate::foundation::consts::{
    BASE_QUANT_MATRIX_STD as BASE_QUANT_STD, BASE_QUANT_MATRIX_XYB as BASE_QUANT_XYB,
    BASE_QUANT_MATRIX_YCBCR as BASE_QUANT_YCBCR,
};

// Re-export global scale factors
pub use crate::foundation::consts::{GLOBAL_SCALE_420, GLOBAL_SCALE_XYB, GLOBAL_SCALE_YCBCR};

// Re-export zero-bias tables
pub use crate::quant::{
    ZERO_BIAS_MUL_XYB, ZERO_BIAS_MUL_YCBCR_HQ, ZERO_BIAS_MUL_YCBCR_LQ, ZERO_BIAS_OFFSET_XYB,
    ZERO_BIAS_OFFSET_YCBCR_AC, ZERO_BIAS_OFFSET_YCBCR_DC,
};

/// Extract the Y (luma) component from a 192-element matrix.
#[inline]
#[must_use]
pub fn luma_from_192(matrix: &[f32; 192]) -> [f32; 64] {
    let mut result = [0.0f32; 64];
    result.copy_from_slice(&matrix[0..64]);
    result
}

/// Extract the Cb (blue chroma) component from a 192-element matrix.
#[inline]
#[must_use]
pub fn cb_from_192(matrix: &[f32; 192]) -> [f32; 64] {
    let mut result = [0.0f32; 64];
    result.copy_from_slice(&matrix[64..128]);
    result
}

/// Extract the Cr (red chroma) component from a 192-element matrix.
#[inline]
#[must_use]
pub fn cr_from_192(matrix: &[f32; 192]) -> [f32; 64] {
    let mut result = [0.0f32; 64];
    result.copy_from_slice(&matrix[128..192]);
    result
}

/// Pack three 64-element components into a 192-element matrix.
#[inline]
#[must_use]
pub fn pack_192(luma: &[f32; 64], cb: &[f32; 64], cr: &[f32; 64]) -> [f32; 192] {
    let mut result = [0.0f32; 192];
    result[0..64].copy_from_slice(luma);
    result[64..128].copy_from_slice(cb);
    result[128..192].copy_from_slice(cr);
    result
}

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

    #[test]
    fn test_extract_components() {
        let luma = luma_from_192(&BASE_QUANT_YCBCR);
        let cb = cb_from_192(&BASE_QUANT_YCBCR);
        let cr = cr_from_192(&BASE_QUANT_YCBCR);

        // Verify extraction matches original
        assert_eq!(&luma[..], &BASE_QUANT_YCBCR[0..64]);
        assert_eq!(&cb[..], &BASE_QUANT_YCBCR[64..128]);
        assert_eq!(&cr[..], &BASE_QUANT_YCBCR[128..192]);
    }

    #[test]
    fn test_pack_roundtrip() {
        let luma = luma_from_192(&BASE_QUANT_YCBCR);
        let cb = cb_from_192(&BASE_QUANT_YCBCR);
        let cr = cr_from_192(&BASE_QUANT_YCBCR);

        let packed = pack_192(&luma, &cb, &cr);
        assert_eq!(packed, BASE_QUANT_YCBCR);
    }

    #[test]
    fn test_zero_bias_table_sizes() {
        assert_eq!(ZERO_BIAS_MUL_YCBCR_LQ.len(), 192);
        assert_eq!(ZERO_BIAS_MUL_YCBCR_HQ.len(), 192);
        assert_eq!(ZERO_BIAS_OFFSET_YCBCR_DC.len(), 3);
        assert_eq!(ZERO_BIAS_OFFSET_YCBCR_AC.len(), 3);
    }
}
