use super::{
    MIC_CHANNELS, MIC_SAMPLE_BYTES, MIC_SAMPLE_RATE, bool_env_enabled, buffer_duration_us,
    explicit_media_sources_required, mic_noise_suppression_from_env, mic_noise_suppression_level,
    mic_packet_target_bytes, pcm_payload_duration_us, split_audio_sample,
};
use gstreamer as gst;
use serial_test::serial;

fn buffer_with_duration(size: usize, duration: Option<gst::ClockTime>) -> gst::Buffer {
    gst::init().ok();
    let mut buffer = gst::Buffer::with_size(size).expect("test buffer");
    buffer
        .get_mut()
        .expect("test buffer should be uniquely owned")
        .set_duration(duration);
    buffer
}

#[test]
fn mic_payload_duration_uses_pcm_frame_count() {
    let ten_ms_bytes = (MIC_SAMPLE_RATE as usize / 100) * MIC_CHANNELS * MIC_SAMPLE_BYTES;

    assert_eq!(pcm_payload_duration_us(ten_ms_bytes), 10_000);
}

#[test]
fn zero_reported_duration_falls_back_to_pcm_payload_duration() {
    let bytes = 1_024 * MIC_CHANNELS * MIC_SAMPLE_BYTES;
    let buffer = buffer_with_duration(bytes, Some(gst::ClockTime::ZERO));

    assert_eq!(buffer_duration_us(buffer.as_ref(), bytes), 21_333);
}

#[test]
fn implausibly_tiny_reported_duration_falls_back_to_payload_duration() {
    let bytes = 1_024 * MIC_CHANNELS * MIC_SAMPLE_BYTES;
    let buffer = buffer_with_duration(bytes, Some(gst::ClockTime::from_useconds(1)));

    assert_eq!(buffer_duration_us(buffer.as_ref(), bytes), 21_333);
}

#[test]
fn plausible_reported_duration_is_preserved() {
    let bytes = 1_024 * MIC_CHANNELS * MIC_SAMPLE_BYTES;
    let buffer = buffer_with_duration(bytes, Some(gst::ClockTime::from_useconds(20_000)));

    assert_eq!(buffer_duration_us(buffer.as_ref(), bytes), 20_000);
}

#[test]
/// Keeps `oversized_microphone_samples_split_into_live_sized_packets` explicit because it sits on microphone capture setup, where host audio stacks expose different source names and latency controls.
/// Inputs are the typed parameters; output is the return value or side effect.
fn oversized_microphone_samples_split_into_live_sized_packets() {
    let bytes_per_frame = MIC_CHANNELS * MIC_SAMPLE_BYTES;
    let hundred_ms_bytes = (MIC_SAMPLE_RATE as usize / 10) * bytes_per_frame;
    let data = vec![7_u8; hundred_ms_bytes];

    let packets = split_audio_sample(1_000_000, &data, mic_packet_target_bytes());

    assert_eq!(packets.len(), 5);
    assert!(packets.iter().all(|packet| packet.id == 0));
    assert!(packets.iter().all(|packet| packet.data.len() == 3_840));
    assert_eq!(packets.front().map(|packet| packet.pts), Some(1_000_000));
    assert_eq!(packets.get(1).map(|packet| packet.pts), Some(1_020_000));
    assert_eq!(packets.back().map(|packet| packet.pts), Some(1_080_000));
}

#[test]
fn trailing_microphone_packet_keeps_remaining_bytes() {
    let bytes_per_frame = MIC_CHANNELS * MIC_SAMPLE_BYTES;
    let forty_five_ms_bytes = ((MIC_SAMPLE_RATE as usize * 45) / 1_000) * bytes_per_frame;
    let data = vec![9_u8; forty_five_ms_bytes];

    let packets = split_audio_sample(5_000, &data, mic_packet_target_bytes());

    assert_eq!(packets.len(), 3);
    assert_eq!(packets[0].data.len(), 3_840);
    assert_eq!(packets[1].data.len(), 3_840);
    assert_eq!(packets[2].data.len(), 960);
    assert_eq!(packets[2].pts, 45_000);
}

#[test]
#[serial]
fn microphone_noise_suppression_level_accepts_named_presets() {
    let cases = [
        ("low", "low"),
        ("medium", "moderate"),
        ("moderate", "moderate"),
        ("high", "high"),
        ("very_high", "very-high"),
        ("aggressive", "very-high"),
        ("unknown", "very-high"),
    ];

    for (raw, expected) in cases {
        temp_env::with_var("LESAVKA_MIC_NOISE_SUPPRESSION_LEVEL", Some(raw), || {
            assert_eq!(mic_noise_suppression_level(), expected);
        });
    }
}

#[test]
#[serial]
fn boolean_microphone_flags_accept_plain_english_true_values() {
    for raw in ["1", "true", "yes", "on"] {
        temp_env::with_vars(
            [
                ("LESAVKA_REQUIRE_EXPLICIT_MEDIA_SOURCES", Some(raw)),
                ("LESAVKA_MIC_NOISE_SUPPRESSION", Some(raw)),
            ],
            || {
                assert!(explicit_media_sources_required());
                assert!(mic_noise_suppression_from_env());
                assert!(bool_env_enabled("LESAVKA_MIC_NOISE_SUPPRESSION"));
            },
        );
    }

    temp_env::with_var("LESAVKA_MIC_NOISE_SUPPRESSION", Some("false"), || {
        assert!(!mic_noise_suppression_from_env());
    });
}
