use super::mjpeg_spool::{mjpeg_spool_enabled, mjpeg_spool_path};

#[test]
fn mjpeg_spool_byte_guard_accepts_jpeg_and_identifies_hevc_annex_b() {
    assert!(super::looks_like_mjpeg_frame(&[
        0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10
    ]));
    assert!(!super::looks_like_mjpeg_frame(&[
        0x00, 0x00, 0x00, 0x01, 0x46, 0x01
    ]));
    assert!(super::looks_like_annex_b_hevc(&[
        0x00, 0x00, 0x00, 0x01, 0x46, 0x01
    ]));
    assert!(super::looks_like_annex_b_hevc(&[0x00, 0x00, 0x01, 0x26]));
    assert!(!super::looks_like_annex_b_hevc(&[0xff, 0xd8, 0xff, 0xdb]));
}

#[test]
fn uvc_session_clock_alignment_defaults_on_and_accepts_disable_overrides() {
    temp_env::with_var_unset("LESAVKA_UVC_SESSION_CLOCK_ALIGN", || {
        assert!(super::uvc_sink_session_clock_align_enabled());
    });

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

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

#[test]
fn mjpeg_uvc_sink_defaults_to_mmap_io_mode_with_safe_override() {
    temp_env::with_var_unset("LESAVKA_UVC_MJPEG_IO_MODE", || {
        assert_eq!(super::uvc_mjpeg_v4l2sink_io_mode(), "mmap");
    });

    temp_env::with_var("LESAVKA_UVC_MJPEG_IO_MODE", Some("mmap"), || {
        assert_eq!(super::uvc_mjpeg_v4l2sink_io_mode(), "mmap");
    });

    temp_env::with_var("LESAVKA_UVC_MJPEG_IO_MODE", Some("not-real"), || {
        assert_eq!(super::uvc_mjpeg_v4l2sink_io_mode(), "mmap");
    });
}

#[test]
fn mjpeg_spool_defaults_on_with_path_override() {
    temp_env::with_var_unset("LESAVKA_UVC_MJPEG_SPOOL", || {
        assert!(mjpeg_spool_enabled());
    });

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

    temp_env::with_var("LESAVKA_UVC_FRAME_PATH", Some("/tmp/frame.mjpg"), || {
        assert_eq!(
            mjpeg_spool_path(),
            std::path::PathBuf::from("/tmp/frame.mjpg")
        );
    });
}

#[test]
fn uvc_appsrc_limits_default_to_freshness_first_bounds() {
    temp_env::with_var_unset("LESAVKA_UVC_APP_MAX_BUFFERS", || {
        temp_env::with_var_unset("LESAVKA_UVC_APP_MAX_BYTES", || {
            temp_env::with_var_unset("LESAVKA_UVC_APP_MAX_TIME_NS", || {
                temp_env::with_var_unset("LESAVKA_UVC_APP_LEAKY_TYPE", || {
                    assert_eq!(super::uvc_appsrc_max_buffers(), 4);
                    assert_eq!(super::uvc_appsrc_max_bytes(), 4 * 1024 * 1024);
                    assert_eq!(super::uvc_appsrc_max_time_ns(), 200_000_000);
                    assert_eq!(super::uvc_appsrc_leaky_type(), "downstream");
                });
            });
        });
    });
}

#[test]
fn uvc_appsrc_limits_accept_positive_safe_overrides_only() {
    temp_env::with_var("LESAVKA_UVC_APP_MAX_BUFFERS", Some("6"), || {
        temp_env::with_var("LESAVKA_UVC_APP_MAX_BYTES", Some("1048576"), || {
            temp_env::with_var("LESAVKA_UVC_APP_MAX_TIME_NS", Some("100000000"), || {
                temp_env::with_var("LESAVKA_UVC_APP_LEAKY_TYPE", Some("upstream"), || {
                    assert_eq!(super::uvc_appsrc_max_buffers(), 6);
                    assert_eq!(super::uvc_appsrc_max_bytes(), 1_048_576);
                    assert_eq!(super::uvc_appsrc_max_time_ns(), 100_000_000);
                    assert_eq!(super::uvc_appsrc_leaky_type(), "upstream");
                });
            });
        });
    });

    temp_env::with_var("LESAVKA_UVC_APP_MAX_BUFFERS", Some("0"), || {
        temp_env::with_var("LESAVKA_UVC_APP_MAX_BYTES", Some("nope"), || {
            temp_env::with_var("LESAVKA_UVC_APP_MAX_TIME_NS", Some("0"), || {
                temp_env::with_var("LESAVKA_UVC_APP_LEAKY_TYPE", Some("sideways"), || {
                    assert_eq!(super::uvc_appsrc_max_buffers(), 4);
                    assert_eq!(super::uvc_appsrc_max_bytes(), 4 * 1024 * 1024);
                    assert_eq!(super::uvc_appsrc_max_time_ns(), 200_000_000);
                    assert_eq!(super::uvc_appsrc_leaky_type(), "downstream");
                });
            });
        });
    });
}

#[test]
fn hevc_spool_freshness_bounds_default_to_tiny_live_handoff() {
    temp_env::with_var_unset("LESAVKA_UVC_HEVC_FRESHNESS_QUEUE_BUFFERS", || {
        temp_env::with_var_unset("LESAVKA_UVC_HEVC_DECODE_MISS_LIMIT", || {
            assert_eq!(super::uvc_hevc_freshness_queue_buffers(), 2);
            assert_eq!(super::uvc_hevc_decode_miss_limit(), 15);
        });
    });
}

#[test]
fn hevc_spool_freshness_bounds_accept_only_small_positive_queue_depths() {
    temp_env::with_var(
        "LESAVKA_UVC_HEVC_FRESHNESS_QUEUE_BUFFERS",
        Some("3"),
        || {
            temp_env::with_var("LESAVKA_UVC_HEVC_DECODE_MISS_LIMIT", Some("4"), || {
                assert_eq!(super::uvc_hevc_freshness_queue_buffers(), 3);
                assert_eq!(super::uvc_hevc_decode_miss_limit(), 4);
            });
        },
    );

    temp_env::with_var(
        "LESAVKA_UVC_HEVC_FRESHNESS_QUEUE_BUFFERS",
        Some("99"),
        || {
            assert_eq!(super::uvc_hevc_freshness_queue_buffers(), 4);
        },
    );

    temp_env::with_var(
        "LESAVKA_UVC_HEVC_FRESHNESS_QUEUE_BUFFERS",
        Some("0"),
        || {
            temp_env::with_var("LESAVKA_UVC_HEVC_DECODE_MISS_LIMIT", Some("0"), || {
                assert_eq!(super::uvc_hevc_freshness_queue_buffers(), 2);
                assert_eq!(super::uvc_hevc_decode_miss_limit(), 15);
            });
        },
    );
}

#[cfg(not(coverage))]
#[test]
fn webcam_bus_watch_stops_promptly_on_drop() {
    use gstreamer as gst;
    use gstreamer::prelude::ElementExt;

    gst::init().expect("gstreamer init");
    let pipeline = gst::Pipeline::new();
    let bus = pipeline.bus().expect("pipeline bus");
    let started = std::time::Instant::now();

    drop(super::WebcamBusWatchHandle::spawn(bus, "test-webcam"));

    assert!(
        started.elapsed() < std::time::Duration::from_secs(1),
        "webcam bus watcher should not outlive dropped webcam sinks"
    );
}
