use super::UpstreamMediaKind;
use crate::calibration::FACTORY_MJPEG_VIDEO_OFFSET_US;
use serial_test::serial;
use std::time::Duration;

#[test]
#[serial(upstream_media_runtime)]
fn upstream_playout_delay_defaults_to_freshness_budget_and_accepts_overrides() {
    temp_env::with_var_unset("LESAVKA_UPSTREAM_PLAYOUT_DELAY_MS", || {
        assert_eq!(super::upstream_playout_delay(), Duration::from_millis(350));
    });

    temp_env::with_var("LESAVKA_UPSTREAM_PLAYOUT_DELAY_MS", Some("250"), || {
        assert_eq!(super::upstream_playout_delay(), Duration::from_millis(250));
    });
}

#[test]
#[serial(upstream_media_runtime)]
fn upstream_bundled_playout_delay_defaults_to_smooth_sync_buffer_and_accepts_overrides() {
    temp_env::with_var_unset("LESAVKA_UPSTREAM_BUNDLED_PLAYOUT_DELAY_MS", || {
        temp_env::with_var_unset("LESAVKA_UPSTREAM_PLAYOUT_DELAY_MS", || {
            assert_eq!(
                super::upstream_bundled_playout_delay(),
                Duration::from_millis(350)
            );
        });
    });

    temp_env::with_var("LESAVKA_UPSTREAM_PLAYOUT_DELAY_MS", Some("250"), || {
        temp_env::with_var_unset("LESAVKA_UPSTREAM_BUNDLED_PLAYOUT_DELAY_MS", || {
            assert_eq!(
                super::upstream_bundled_playout_delay(),
                Duration::from_millis(250)
            );
        });
    });

    temp_env::with_var(
        "LESAVKA_UPSTREAM_BUNDLED_PLAYOUT_DELAY_MS",
        Some("40"),
        || {
            assert_eq!(
                super::upstream_bundled_playout_delay(),
                Duration::from_millis(40)
            );
        },
    );
}

#[test]
#[serial(upstream_media_runtime)]
fn upstream_max_live_lag_defaults_to_one_second_and_accepts_overrides() {
    temp_env::with_var_unset("LESAVKA_UPSTREAM_MAX_LIVE_LAG_MS", || {
        assert_eq!(super::upstream_max_live_lag(), Duration::from_secs(1));
    });

    temp_env::with_var("LESAVKA_UPSTREAM_MAX_LIVE_LAG_MS", Some("750"), || {
        assert_eq!(super::upstream_max_live_lag(), Duration::from_millis(750));
    });

    temp_env::with_var("LESAVKA_UPSTREAM_MAX_LIVE_LAG_MS", Some("5000"), || {
        assert_eq!(super::upstream_max_live_lag(), Duration::from_secs(1));
    });
}

#[test]
#[serial(upstream_media_runtime)]
fn upstream_startup_timeout_defaults_to_one_minute_and_accepts_overrides() {
    temp_env::with_var_unset("LESAVKA_UPSTREAM_STARTUP_TIMEOUT_MS", || {
        assert_eq!(super::upstream_startup_timeout(), Duration::from_secs(60));
    });

    temp_env::with_var("LESAVKA_UPSTREAM_STARTUP_TIMEOUT_MS", Some("2500"), || {
        assert_eq!(
            super::upstream_startup_timeout(),
            Duration::from_millis(2500)
        );
    });
}

#[test]
#[serial(upstream_media_runtime)]
fn upstream_requires_paired_startup_by_default_with_compatibility_override() {
    temp_env::with_var_unset("LESAVKA_UPSTREAM_REQUIRE_PAIRED_STARTUP", || {
        assert!(super::upstream_require_paired_startup());
    });

    for disabled in ["0", "false", "no", "off"] {
        temp_env::with_var(
            "LESAVKA_UPSTREAM_REQUIRE_PAIRED_STARTUP",
            Some(disabled),
            || {
                assert!(!super::upstream_require_paired_startup());
            },
        );
    }

    temp_env::with_var("LESAVKA_UPSTREAM_REQUIRE_PAIRED_STARTUP", Some("1"), || {
        assert!(super::upstream_require_paired_startup());
    });
}

#[test]
#[serial(upstream_media_runtime)]
fn upstream_playout_offsets_default_to_mjpeg_calibration_and_accept_overrides() {
    temp_env::with_var_unset("LESAVKA_UPSTREAM_AUDIO_PLAYOUT_OFFSET_US", || {
        temp_env::with_var_unset("LESAVKA_UPSTREAM_VIDEO_PLAYOUT_OFFSET_US", || {
            assert_eq!(
                super::upstream_playout_offset_us(UpstreamMediaKind::Microphone),
                0
            );
            assert_eq!(
                super::upstream_playout_offset_us(UpstreamMediaKind::Camera),
                FACTORY_MJPEG_VIDEO_OFFSET_US
            );
        });
    });

    temp_env::with_var(
        "LESAVKA_UPSTREAM_AUDIO_PLAYOUT_OFFSET_US",
        Some("-20000"),
        || {
            temp_env::with_var(
                "LESAVKA_UPSTREAM_VIDEO_PLAYOUT_OFFSET_US",
                Some("35000"),
                || {
                    assert_eq!(
                        super::upstream_playout_offset_us(UpstreamMediaKind::Microphone),
                        -20_000
                    );
                    assert_eq!(
                        super::upstream_playout_offset_us(UpstreamMediaKind::Camera),
                        35_000
                    );
                },
            );
        },
    );
}

#[test]
#[serial(upstream_media_runtime)]
fn bundled_playout_offsets_default_to_runtime_calibration_and_accept_explicit_overrides() {
    temp_env::with_var_unset("LESAVKA_UPSTREAM_BUNDLED_AUDIO_PLAYOUT_OFFSET_US", || {
        temp_env::with_var_unset("LESAVKA_UPSTREAM_BUNDLED_VIDEO_PLAYOUT_OFFSET_US", || {
            assert_eq!(
                super::upstream_bundled_playout_offset_override_us(UpstreamMediaKind::Microphone),
                None
            );
            assert_eq!(
                super::upstream_bundled_playout_offset_override_us(UpstreamMediaKind::Camera),
                None
            );
        });
    });

    temp_env::with_var(
        "LESAVKA_UPSTREAM_BUNDLED_AUDIO_PLAYOUT_OFFSET_US",
        Some("12000"),
        || {
            temp_env::with_var(
                "LESAVKA_UPSTREAM_BUNDLED_VIDEO_PLAYOUT_OFFSET_US",
                Some("-3000"),
                || {
                    assert_eq!(
                        super::upstream_bundled_playout_offset_override_us(
                            UpstreamMediaKind::Microphone
                        ),
                        Some(12_000)
                    );
                    assert_eq!(
                        super::upstream_bundled_playout_offset_override_us(
                            UpstreamMediaKind::Camera
                        ),
                        Some(-3_000)
                    );
                },
            );
        },
    );
}

#[test]
#[serial(upstream_media_runtime)]
fn upstream_pairing_master_slack_defaults_to_eighty_ms_and_accepts_overrides() {
    temp_env::with_var_unset("LESAVKA_UPSTREAM_PAIR_SLACK_US", || {
        assert_eq!(
            super::upstream_pairing_master_slack(),
            Duration::from_micros(80_000)
        );
    });

    temp_env::with_var("LESAVKA_UPSTREAM_PAIR_SLACK_US", Some("5000"), || {
        assert_eq!(
            super::upstream_pairing_master_slack(),
            Duration::from_micros(5_000)
        );
    });
}

#[test]
#[serial(upstream_media_runtime)]
fn upstream_audio_master_wait_grace_defaults_to_sync_buffer_and_accepts_overrides() {
    temp_env::with_var_unset("LESAVKA_UPSTREAM_AUDIO_MASTER_WAIT_GRACE_MS", || {
        assert_eq!(
            super::upstream_audio_master_wait_grace(),
            Duration::from_millis(350)
        );
    });

    temp_env::with_var(
        "LESAVKA_UPSTREAM_AUDIO_MASTER_WAIT_GRACE_MS",
        Some("125"),
        || {
            assert_eq!(
                super::upstream_audio_master_wait_grace(),
                Duration::from_millis(125)
            );
        },
    );
}

#[test]
#[serial(upstream_media_runtime)]
fn upstream_reanchor_late_threshold_defaults_to_half_the_buffer_and_accepts_overrides() {
    temp_env::with_var_unset("LESAVKA_UPSTREAM_REANCHOR_LATE_MS", || {
        assert_eq!(
            super::upstream_reanchor_late_threshold(Duration::from_secs(1)),
            Duration::from_millis(500)
        );
        assert_eq!(
            super::upstream_reanchor_late_threshold(Duration::from_millis(100)),
            Duration::from_millis(100)
        );
    });

    temp_env::with_var("LESAVKA_UPSTREAM_REANCHOR_LATE_MS", Some("42"), || {
        assert_eq!(
            super::upstream_reanchor_late_threshold(Duration::from_secs(1)),
            Duration::from_millis(42)
        );
    });
}

#[test]
#[serial(upstream_media_runtime)]
fn upstream_timing_trace_flag_accepts_false_values() {
    temp_env::with_var("LESAVKA_UPSTREAM_TIMING_TRACE", Some("off"), || {
        assert!(!super::upstream_timing_trace_enabled());
    });
    temp_env::with_var("LESAVKA_UPSTREAM_TIMING_TRACE", Some("false"), || {
        assert!(!super::upstream_timing_trace_enabled());
    });
    temp_env::with_var("LESAVKA_UPSTREAM_TIMING_TRACE", Some("1"), || {
        assert!(super::upstream_timing_trace_enabled());
    });
}

#[test]
#[serial(upstream_media_runtime)]
fn apply_playout_offset_supports_negative_offsets() {
    let base = tokio::time::Instant::now() + Duration::from_millis(50);
    let shifted = super::apply_playout_offset(base, -20_000);
    let delta = base.saturating_duration_since(shifted);
    assert_eq!(delta, Duration::from_micros(20_000));
}

#[test]
#[serial(upstream_media_runtime)]
fn apply_playout_offset_supports_positive_offsets() {
    let base = tokio::time::Instant::now();
    let shifted = super::apply_playout_offset(base, 30_000);
    let delta = shifted.saturating_duration_since(base);
    assert_eq!(delta, Duration::from_micros(30_000));
}
