use opus_rs::range_coder::RangeCoder;
/// Test SILK decoder against C reference encoded data
/// This test uses bitstreams generated by the C opus library (opus-1.6)
use opus_rs::silk::dec_api::SilkDecoder;
use opus_rs::silk::decode_frame::FLAG_DECODE_NORMAL;
use opus_rs::silk::resampler::SilkResampler;

mod hex {
    pub fn encode(data: &[u8]) -> String {
        let mut s = String::with_capacity(data.len() * 2);
        for &b in data {
            let _ = std::fmt::Write::write_fmt(&mut s, format_args!("{:02x}", b));
        }
        s
    }
}

/// C reference encoded bitstream for 440Hz sine wave at 8kHz, 20ms frame
/// Generated by: opus_encode_float() with 10kbps CBR, complexity 0
/// Input: sin(2*pi*440*i/8000) for i in 0..160
const C_ENCODED_8KHZ_20MS: &[u8] = &[
    0x0b, 0x01, 0x84, 0xc1, 0xc1, 0xc7, 0xb6, 0x6f, 0x5e, 0x06, 0xa4, 0xb7, 0x28, 0xc8, 0x1c, 0x95,
    0x61, 0x20, 0xe0, 0x78, 0x1c, 0x26, 0x4a, 0x17, 0x60,
];

/// C reference decoded output (160 samples at 8kHz = 20ms)
/// Generated by opus_decode() from the above encoded data
const C_DECODED_OUTPUT: [i16; 160] = [
    0, 0, 0, 0, 0, 96, 88, -40, -221, -254, -140, -137, -50, 143, 196, 308, 312, 170, -49, -142,
    -98, -174, -159, -17, 188, 442, 705, 769, 816, 892, 940, 957, 931, 694, 468, 144, -285, -539,
    -615, -548, -359, -71, 286, 669, 859, 615, 23, -133, -511, -579, -194, 398, 534, 9881, 17993,
    24112, 27741, 27748, 22514, 14768, 6459, -4981, -14998, -22576, -27136, -28032, -28689, -25749,
    -19147, -10515, -1472, 6676, 14070, 19202, 22220, 23035, 21366, 16971, 10466, 2930, -4784,
    -11799, -19794, -24772, -28815, -29737, -26770, -20986, -12941, -2659, 7189, 16824, 24320,
    28228, 28996, 26677, 21352, 13676, 4720, -5720, -15126, -21808, -25876, -26722, -24395, -19678,
    -12851, -4686, 3415, 10846, 16881, 20841, 22387, 21458, 18307, 13037, 6373, -430, -6965,
    -12590, -16299, -18131, -17694, -15420, -11394, -5332, 1854, 8371, 14311, 18235, 19646, 19002,
    15403, 10174, 3355, -3381, -10082, -15317, -18443, -19567, -18499, -14524, -9203, -2225, 5588,
    13002, 18315, 21218, 21622, 19489, 14464, 8000, 257, -7033, -14071, -19362, -21837, -21914,
    -19643, -15421,
];

/// Decode TOC byte
fn parse_toc(toc: u8) -> (i32, i32, i32) {
    // SILK-only TOC format: [bw:2][config:3][s:1][c:2]
    let bandwidth = (toc >> 5) & 0x03;
    let config = (toc >> 3) & 0x07;
    let frame_count_code = toc & 0x03;

    // Map bandwidth to sample rate
    let sample_rate_hz = match bandwidth {
        0 => 8000,  // NB
        1 => 12000, // MB
        2 => 16000, // WB
        _ => 24000, // SWB/FB (shouldn't happen for SILK)
    };

    (sample_rate_hz, config as i32, frame_count_code as i32)
}

/// Test decoding C-encoded SILK bitstream
#[test]
fn test_decode_c_encoded_silk_8khz() {
    // Parse TOC byte
    let toc = C_ENCODED_8KHZ_20MS[0];
    let (sample_rate_hz, _config, frame_count_code) = parse_toc(toc);

    println!("TOC: 0x{:02x}", toc);
    println!("Sample rate: {} Hz", sample_rate_hz);
    println!("Frame count code: {}", frame_count_code);

    assert_eq!(sample_rate_hz, 8000, "Expected 8kHz sample rate");

    // Initialize decoder
    let mut decoder = SilkDecoder::new();
    let ret = decoder.init(sample_rate_hz, 1);
    assert_eq!(ret, 0, "Failed to initialize decoder");

    // Get frame length
    let frame_length = decoder.frame_length();
    println!("Decoder frame length: {}", frame_length);
    assert_eq!(frame_length, 160, "Expected 160 samples frame length");

    // The SILK payload starts after TOC byte
    let silk_payload = &C_ENCODED_8KHZ_20MS[1..];
    println!("SILK payload: {} bytes", silk_payload.len());
    println!("SILK hex: {}", hex::encode(silk_payload));

    // Create range decoder
    let mut range_coder = RangeCoder::new_decoder(&silk_payload);

    // Decode
    let mut output = vec![0i16; 160];
    let n_samples = decoder.decode(
        &mut range_coder,
        &mut output,
        FLAG_DECODE_NORMAL,
        true,
        20,
        8000,
    );

    println!("Decoded {} samples", n_samples);
    println!();

    // Print comparison
    println!("=== Comparison with C reference ===");
    println!("Rust output [0..20]: {:?}", &output[..20]);
    println!("C reference [0..20]: {:?}", &C_DECODED_OUTPUT[..20]);
    println!();

    // Calculate and compare RMS energy
    let sum_sq: i64 = output[..n_samples as usize]
        .iter()
        .map(|&x| (x as i64) * (x as i64))
        .sum();
    let rust_rms = ((sum_sq as f64) / (n_samples as f64)).sqrt();

    let c_sum_sq: i64 = C_DECODED_OUTPUT
        .iter()
        .map(|&x| (x as i64) * (x as i64))
        .sum();
    let c_rms = ((c_sum_sq as f64) / (C_DECODED_OUTPUT.len() as f64)).sqrt();

    println!("Rust RMS energy: {:.2}", rust_rms);
    println!("C reference RMS: {:.2}", c_rms);
    println!("RMS ratio: {:.4}", rust_rms / c_rms);
    println!();

    // Calculate correlation
    let mut dot_product: i64 = 0;
    let mut rust_norm: i64 = 0;
    let mut c_norm: i64 = 0;
    for i in 0..n_samples as usize {
        dot_product += (output[i] as i64) * (C_DECODED_OUTPUT[i] as i64);
        rust_norm += (output[i] as i64) * (output[i] as i64);
        c_norm += (C_DECODED_OUTPUT[i] as i64) * (C_DECODED_OUTPUT[i] as i64);
    }
    let correlation = if rust_norm > 0 && c_norm > 0 {
        (dot_product as f64) / ((rust_norm as f64).sqrt() * (c_norm as f64).sqrt())
    } else {
        0.0
    };
    println!("Correlation: {:.4}", correlation);

    // Check for non-zero output
    let non_zero_count = output[..n_samples as usize]
        .iter()
        .filter(|&&x| x != 0)
        .count();
    println!("Non-zero samples: {} / {}", non_zero_count, n_samples);

    // Basic sanity check
    assert!(non_zero_count > 0, "Output is all zeros");
}

/// Test decoder with synthetic 16kHz data
#[test]
fn test_decode_synth_16khz() {
    let sample_rate = 16000;
    let frame_size = 320; // 20ms at 16kHz

    // Initialize decoder
    let mut decoder = SilkDecoder::new();
    let ret = decoder.init(sample_rate, 1);
    assert_eq!(ret, 0, "Failed to initialize decoder");
    assert_eq!(decoder.frame_length(), frame_size);

    // Create a minimal valid SILK bitstream
    // TOC byte for 16kHz, 20ms: bandwidth=2 (WB), config=0 (10ms frames x2), stereo=0, code=0
    // Actually, for 20ms frames: config maps to frame durations
    // config 0 = 10ms, 1 = 20ms, 2 = 40ms, 3 = 60ms (for SILK)
    let toc: u8 = 0b10_001_0_00; // WB, 20ms frame, mono, 1 frame
    println!("TOC for 16kHz 20ms: 0x{:02x}", toc);

    // We need actual encoded data to decode, which we don't have
    // So this test just verifies decoder initialization works
    println!("Decoder initialized successfully for 16kHz");
}

/// Test decoder reset functionality
#[test]
fn test_decoder_reset() {
    let mut decoder = SilkDecoder::new();

    // Initialize at 16kHz
    let ret = decoder.init(16000, 1);
    assert_eq!(ret, 0, "Init 16kHz failed");
    assert_eq!(decoder.sample_rate(), 16000);

    // Reset and reinit at 8kHz
    decoder.reset();
    let ret = decoder.init(8000, 1);
    assert_eq!(ret, 0, "Init 8kHz failed");
    assert_eq!(decoder.sample_rate(), 8000);

    // Verify state is reset
    assert_eq!(decoder.channel_state[0].first_frame_after_reset, 1);
}

/// Test that decoder handles invalid sample rates correctly
#[test]
fn test_decoder_invalid_sample_rate() {
    let mut decoder = SilkDecoder::new();

    // SILK only supports 8, 12, 16 kHz
    let ret = decoder.init(48000, 1);
    assert!(ret < 0, "Should reject 48kHz");

    let ret = decoder.init(44100, 1);
    assert!(ret < 0, "Should reject 44.1kHz");

    let ret = decoder.init(24000, 1);
    assert!(ret < 0, "Should reject 24kHz");
}

/// Test SilkResampler: 8kHz → 48kHz (IirFir mode)
#[test]
fn test_resampler_8khz_to_48khz() {
    let mut resampler = SilkResampler::default();
    let ret = resampler.init(8000, 48000);
    assert_eq!(ret, 0, "Resampler init should succeed for 8→48kHz");

    // Input: 80 samples at 8kHz (10ms)
    let mut input = vec![0i16; 80];
    for i in 0..80 {
        // 440 Hz sine wave at 8kHz
        let phase = 2.0f32 * std::f32::consts::PI * 440.0 * i as f32 / 8000.0;
        input[i] = (phase.sin() * 16384.0) as i16;
    }

    // Output: 6x more samples = 480 samples at 48kHz (10ms)
    let mut output = vec![0i16; 480];
    let ret = resampler.process(&mut output, &input, 80);
    assert_eq!(ret, 0, "Resampler process should succeed");

    // Output should have significant non-zero content
    let nonzero = output.iter().filter(|&&x| x != 0).count();
    assert!(nonzero > 0, "Resampler output should not be all-zero");

    // Energy ratio: output energy should be in same ballpark as input
    let in_energy: i64 = input.iter().map(|&x| (x as i64) * (x as i64)).sum();
    let out_energy: i64 = output.iter().map(|&x| (x as i64) * (x as i64)).sum();
    let ratio = out_energy as f64 / in_energy as f64;

    println!("8kHz→48kHz resampler:");
    println!("  Input energy: {}", in_energy);
    println!("  Output energy: {}", out_energy);
    println!("  Energy ratio (should be ~6): {:.2}", ratio);
    println!("  Non-zero samples: {}/480", nonzero);

    // Energy should be in reasonable range (not zero, not wildly wrong)
    assert!(out_energy > 0, "Output energy must be non-zero");
}

/// Test SilkResampler: 12kHz → 24kHz (Up2HQ mode, direct 2x upsample)
#[test]
fn test_resampler_12khz_to_24khz() {
    let mut resampler = SilkResampler::default();
    let ret = resampler.init(12000, 24000);
    assert_eq!(ret, 0, "Resampler init should succeed for 12→24kHz");

    // Input: 120 samples at 12kHz (10ms)
    let mut input = vec![0i16; 120];
    for i in 0..120 {
        let phase = 2.0f32 * std::f32::consts::PI * 400.0 * i as f32 / 12000.0;
        input[i] = (phase.sin() * 16384.0) as i16;
    }

    // Output: 240 samples at 24kHz (10ms)
    let mut output = vec![0i16; 240];
    let ret = resampler.process(&mut output, &input, 120);
    assert_eq!(ret, 0, "Resampler process should succeed");

    let nonzero = output.iter().filter(|&&x| x != 0).count();
    assert!(
        nonzero > 0,
        "12→24kHz resampler output should not be all-zero"
    );

    let in_energy: i64 = input.iter().map(|&x| (x as i64) * (x as i64)).sum();
    let out_energy: i64 = output.iter().map(|&x| (x as i64) * (x as i64)).sum();

    println!("12kHz→24kHz resampler (Up2HQ):");
    println!("  Input energy: {}", in_energy);
    println!("  Output energy: {}", out_energy);
    println!("  Non-zero samples: {}/240", nonzero);

    assert!(out_energy > 0, "Output energy must be non-zero");
}

/// Test SilkResampler: 16kHz → 48kHz (IirFir mode)
#[test]
fn test_resampler_16khz_to_48khz() {
    let mut resampler = SilkResampler::default();
    let ret = resampler.init(16000, 48000);
    assert_eq!(ret, 0, "Resampler init should succeed for 16→48kHz");

    // Input: 160 samples at 16kHz (10ms)
    let mut input = vec![0i16; 160];
    for i in 0..160 {
        let phase = 2.0f32 * std::f32::consts::PI * 440.0 * i as f32 / 16000.0;
        input[i] = (phase.sin() * 16384.0) as i16;
    }

    // Output: 480 samples at 48kHz (10ms)
    let mut output = vec![0i16; 480];
    let ret = resampler.process(&mut output, &input, 160);
    assert_eq!(ret, 0, "Resampler process should succeed");

    let nonzero = output.iter().filter(|&&x| x != 0).count();
    assert!(
        nonzero > 0,
        "16→48kHz resampler output should not be all-zero"
    );

    let out_energy: i64 = output.iter().map(|&x| (x as i64) * (x as i64)).sum();
    println!("16kHz→48kHz resampler:");
    println!("  Output energy: {}", out_energy);
    println!("  Non-zero samples: {}/480", nonzero);

    assert!(out_energy > 0, "Output energy must be non-zero");
}

/// Test SilkResampler: 8kHz → 8kHz (Copy mode - no resampling)
#[test]
fn test_resampler_8khz_copy_mode() {
    let mut resampler = SilkResampler::default();
    let ret = resampler.init(8000, 8000);
    assert_eq!(ret, 0, "Resampler init should succeed for 8→8kHz copy mode");

    let mut input = vec![0i16; 80];
    for i in 0..80 {
        let phase = 2.0f32 * std::f32::consts::PI * 440.0 * i as f32 / 8000.0;
        input[i] = (phase.sin() * 16384.0) as i16;
    }

    let mut output = vec![0i16; 80];
    let ret = resampler.process(&mut output, &input, 80);
    assert_eq!(ret, 0, "Copy mode process should succeed");

    println!("8kHz→8kHz copy mode: output[0..5]={:?}", &output[..5]);
}

/// Test SilkResampler: delay buffer state persists correctly across multiple calls
#[test]
fn test_resampler_delay_buffer_continuity() {
    let mut resampler = SilkResampler::default();
    let ret = resampler.init(8000, 48000);
    assert_eq!(ret, 0, "Resampler init should succeed");

    let frame_size_in = 80; // 10ms at 8kHz
    let frame_size_out = 480; // 10ms at 48kHz

    // Process 5 consecutive frames and verify output energy stays consistent
    let mut energies = Vec::new();
    let mut prev_output_end = 0i16;

    for frame_idx in 0..5 {
        let mut input = vec![0i16; frame_size_in];
        for i in 0..frame_size_in {
            let t = (frame_idx * frame_size_in + i) as f32 / 8000.0;
            let phase = 2.0f32 * std::f32::consts::PI * 440.0 * t;
            input[i] = (phase.sin() * 16384.0) as i16;
        }

        let mut output = vec![0i16; frame_size_out];
        let ret = resampler.process(&mut output, &input, frame_size_in as i32);
        assert_eq!(ret, 0, "Frame {} process should succeed", frame_idx);

        let energy: i64 = output.iter().map(|&x| (x as i64) * (x as i64)).sum();
        energies.push(energy);

        // Check for discontinuities between frames (last sample of prev vs first of current)
        if frame_idx > 0 {
            let jump = (output[0] as i32 - prev_output_end as i32).abs();
            println!(
                "Frame {}: energy={}, jump from previous frame={}",
                frame_idx, energy, jump
            );
        } else {
            println!("Frame {}: energy={}", frame_idx, energy);
        }
        prev_output_end = output[frame_size_out - 1];
    }

    // All frames (after the first warm-up) should have non-zero energy
    for (i, &e) in energies.iter().enumerate().skip(1) {
        assert!(e > 0, "Frame {} should have non-zero energy, got {}", i, e);
    }

    println!("✅ Delay buffer continuity test passed: {:?}", energies);
}

/// Test SilkResampler: 8kHz → 16kHz (IirFir mode)
#[test]
fn test_resampler_8khz_to_16khz() {
    let mut resampler = SilkResampler::default();
    let ret = resampler.init(8000, 16000);
    assert_eq!(ret, 0, "Resampler init should succeed for 8→16kHz");

    let mut input = vec![0i16; 80];
    for i in 0..80 {
        let phase = 2.0f32 * std::f32::consts::PI * 440.0 * i as f32 / 8000.0;
        input[i] = (phase.sin() * 16384.0) as i16;
    }

    let mut output = vec![0i16; 160];
    let ret = resampler.process(&mut output, &input, 80);
    assert_eq!(ret, 0, "Resampler process should succeed");

    let nonzero = output.iter().filter(|&&x| x != 0).count();
    let out_energy: i64 = output.iter().map(|&x| (x as i64) * (x as i64)).sum();

    println!("8kHz→16kHz resampler:");
    println!("  Output energy: {}", out_energy);
    println!("  Non-zero samples: {}/160", nonzero);

    assert!(
        nonzero > 0,
        "8→16kHz resampler output should not be all-zero"
    );
    assert!(out_energy > 0, "Output energy must be non-zero");
}
