// Integration smoke coverage for server camera sink constructors.
//
// Scope: exercise public sink and relay constructors with resilient
// assertions that tolerate host-specific media capabilities.
// Targets: `server/src/video_sinks.rs`.
// Why: sink setup contains substantial branch logic that should be executed
// in CI even when real HDMI/UVC hardware is unavailable.

use lesavka_common::lesavka::VideoPacket;
use lesavka_server::camera::{CameraCodec, CameraConfig, CameraOutput};
use lesavka_server::video::{CameraRelay, HdmiSink, WebcamSink};
use serial_test::serial;
use temp_env::with_var;

fn hdmi_config(codec: CameraCodec) -> CameraConfig {
    CameraConfig {
        output: CameraOutput::Hdmi,
        codec,
        width: 640,
        height: 360,
        fps: 30,
        hdmi: None,
    }
}

#[test]
#[serial]
fn webcam_sink_constructor_is_stable_for_missing_uvc_device() {
    let cfg = hdmi_config(CameraCodec::Mjpeg);
    match WebcamSink::new("/dev/video-definitely-missing", &cfg) {
        Ok(sink) => sink.push(VideoPacket {
            id: 2,
            pts: 0,
            data: vec![0xFF, 0xD8, 0xFF, 0xD9],
            ..Default::default()
        }),
        Err(err) => assert!(!err.to_string().trim().is_empty()),
    }
}

#[test]
#[serial]
fn hdmi_sink_constructor_and_push_are_stable_with_override() {
    with_var("LESAVKA_HDMI_SINK", Some("fakesink"), || {
        let cfg = hdmi_config(CameraCodec::H264);
        match HdmiSink::new(&cfg) {
            Ok(sink) => sink.push(VideoPacket {
                id: 2,
                pts: 0,
                data: vec![0, 0, 0, 1, 0x65],
                ..Default::default()
            }),
            Err(err) => assert!(!err.to_string().trim().is_empty()),
        }
    });
}

#[test]
#[serial]
fn camera_relay_hdmi_constructor_and_feed_are_stable() {
    with_var("LESAVKA_HDMI_SINK", Some("fakesink"), || {
        let cfg = hdmi_config(CameraCodec::Mjpeg);
        match CameraRelay::new_hdmi(7, &cfg) {
            Ok(relay) => relay.feed(VideoPacket {
                id: 2,
                pts: 123,
                data: vec![0xFF, 0xD8, 0xFF, 0xD9],
                ..Default::default()
            }),
            Err(err) => assert!(!err.to_string().trim().is_empty()),
        }
    });
}

#[test]
#[serial]
fn camera_relay_uvc_constructor_is_stable_for_missing_device() {
    let cfg = hdmi_config(CameraCodec::Mjpeg);
    match CameraRelay::new_uvc(9, "/dev/video-definitely-missing", &cfg) {
        Ok(relay) => relay.feed(VideoPacket {
            id: 2,
            pts: 321,
            data: vec![0xFF, 0xD8, 0xFF, 0xD9],
            ..Default::default()
        }),
        Err(err) => assert!(!err.to_string().trim().is_empty()),
    }
}

#[test]
#[serial]
fn webcam_sink_h264_constructor_path_is_stable() {
    let cfg = hdmi_config(CameraCodec::H264);
    match WebcamSink::new("/dev/video-definitely-missing", &cfg) {
        Ok(sink) => sink.push(VideoPacket {
            id: 3,
            pts: 55,
            data: vec![0, 0, 0, 1, 0x65],
            ..Default::default()
        }),
        Err(err) => assert!(!err.to_string().trim().is_empty()),
    }
}

#[test]
#[serial]
fn hdmi_sink_mjpeg_constructor_path_is_stable() {
    with_var("LESAVKA_HDMI_SINK", Some("fakesink"), || {
        let cfg = hdmi_config(CameraCodec::Mjpeg);
        match HdmiSink::new(&cfg) {
            Ok(sink) => sink.push(VideoPacket {
                id: 4,
                pts: 99,
                data: vec![0xFF, 0xD8, 0xFF, 0xD9],
                ..Default::default()
            }),
            Err(err) => assert!(!err.to_string().trim().is_empty()),
        }
    });
}

#[test]
#[serial]
fn hdmi_sink_override_with_invalid_element_returns_error() {
    with_var(
        "LESAVKA_HDMI_SINK",
        Some("definitely-not-a-real-gst-element"),
        || {
            let cfg = hdmi_config(CameraCodec::H264);
            let result = HdmiSink::new(&cfg);
            assert!(
                result.is_err(),
                "invalid sink override should fail construction"
            );
        },
    );
}
