// Integration coverage for the server camera-selection contract.
//
// Scope: exercise environment-driven camera mode selection and stable enum
// string mappings via the public camera module API.
// Targets: `server/src/camera.rs`.
// Why: camera policy decides the entire stream transport path, so these
// behavior contracts belong in centralized test harness.

use lesavka_server::camera::{
    CameraCodec, CameraOutput, current_camera_config, update_camera_config,
};
use serial_test::serial;
use temp_env::with_var;

#[test]
fn camera_enum_strings_are_stable() {
    assert_eq!(CameraOutput::Uvc.as_str(), "uvc");
    assert_eq!(CameraOutput::Hdmi.as_str(), "hdmi");
    assert_eq!(CameraCodec::Mjpeg.as_str(), "mjpeg");
    assert_eq!(CameraCodec::H264.as_str(), "h264");
    assert_eq!(CameraCodec::Hevc.as_str(), "hevc");
}

#[test]
#[serial]
fn camera_config_uses_interval_when_fps_is_unset_or_invalid() {
    with_var("LESAVKA_CAM_OUTPUT", Some("uvc"), || {
        with_var("LESAVKA_UVC_WIDTH", Some("640"), || {
            with_var("LESAVKA_UVC_HEIGHT", Some("360"), || {
                with_var("LESAVKA_UVC_FPS", None::<&str>, || {
                    with_var("LESAVKA_UVC_INTERVAL", Some("250000"), || {
                        let cfg = update_camera_config();
                        assert_eq!(cfg.output, CameraOutput::Uvc);
                        assert_eq!(cfg.codec, CameraCodec::Hevc);
                        assert_eq!(cfg.width, 640);
                        assert_eq!(cfg.height, 360);
                        assert_eq!(cfg.fps, 40);
                    });
                });

                with_var("LESAVKA_UVC_FPS", Some("not-a-number"), || {
                    with_var("LESAVKA_UVC_INTERVAL", Some("250000"), || {
                        let cfg = update_camera_config();
                        assert_eq!(cfg.output, CameraOutput::Uvc);
                        assert_eq!(cfg.codec, CameraCodec::Hevc);
                        assert_eq!(cfg.width, 640);
                        assert_eq!(cfg.height, 360);
                        assert_eq!(cfg.fps, 40);
                    });
                });
            });
        });
    });
}

#[test]
#[serial]
fn camera_config_zero_interval_falls_back_to_default_fps() {
    with_var("LESAVKA_CAM_OUTPUT", Some("uvc"), || {
        with_var("LESAVKA_UVC_WIDTH", Some("800"), || {
            with_var("LESAVKA_UVC_HEIGHT", Some("600"), || {
                with_var("LESAVKA_UVC_FPS", None::<&str>, || {
                    with_var("LESAVKA_UVC_INTERVAL", Some("0"), || {
                        let cfg = update_camera_config();
                        assert_eq!(cfg.output, CameraOutput::Uvc);
                        assert_eq!(cfg.codec, CameraCodec::Hevc);
                        assert_eq!(cfg.width, 800);
                        assert_eq!(cfg.height, 600);
                        assert_eq!(cfg.fps, 30);
                    });
                });
            });
        });
    });
}

#[test]
#[serial]
fn camera_config_forced_hdmi_defaults_to_mjpeg_without_hardware_decode() {
    with_var("LESAVKA_CAM_OUTPUT", Some("hdmi"), || {
        with_var("LESAVKA_HW_H264", None::<&str>, || {
            with_var("LESAVKA_CAM_CODEC", None::<&str>, || {
                let cfg = update_camera_config();
                assert_eq!(cfg.output, CameraOutput::Hdmi);
                assert_eq!(cfg.codec, CameraCodec::Mjpeg);
                assert_eq!(cfg.width, 1280);
                assert_eq!(cfg.height, 720);
                assert_eq!(cfg.fps, 30);

                let cached = current_camera_config();
                assert_eq!(cached.output, CameraOutput::Hdmi);
                assert_eq!(cached.codec, CameraCodec::Mjpeg);
                assert_eq!(cached.width, 1280);
                assert_eq!(cached.height, 720);
                assert_eq!(cached.fps, 30);
            });
        });
    });
}

#[test]
#[serial]
fn camera_config_forced_hdmi_honors_1080p_uplink_override() {
    with_var("LESAVKA_CAM_OUTPUT", Some("hdmi"), || {
        with_var("LESAVKA_HW_H264", None::<&str>, || {
            with_var("LESAVKA_CAM_WIDTH", Some("1920"), || {
                with_var("LESAVKA_CAM_HEIGHT", Some("1080"), || {
                    with_var("LESAVKA_CAM_FPS", Some("30"), || {
                        with_var("LESAVKA_CAM_CODEC", None::<&str>, || {
                            let cfg = update_camera_config();
                            assert_eq!(cfg.output, CameraOutput::Hdmi);
                            assert_eq!(cfg.codec, CameraCodec::Mjpeg);
                            assert_eq!(cfg.width, 1920);
                            assert_eq!(cfg.height, 1080);
                            assert_eq!(cfg.fps, 30);
                        });
                    });
                });
            });
        });
    });
}

#[test]
#[serial]
fn camera_config_forced_hdmi_honors_explicit_h264_override() {
    with_var("LESAVKA_CAM_OUTPUT", Some("hdmi"), || {
        with_var("LESAVKA_HW_H264", None::<&str>, || {
            with_var("LESAVKA_CAM_CODEC", Some("h264"), || {
                let cfg = update_camera_config();
                assert_eq!(cfg.output, CameraOutput::Hdmi);
                assert_eq!(cfg.codec, CameraCodec::H264);
                assert_eq!(cfg.width, 1280);
                assert_eq!(cfg.height, 720);
                assert_eq!(cfg.fps, 30);
            });
        });
    });
}

#[test]
#[serial]
fn camera_config_output_override_is_case_insensitive() {
    with_var("LESAVKA_CAM_OUTPUT", Some("  UVC  "), || {
        with_var("LESAVKA_UVC_WIDTH", Some("1024"), || {
            with_var("LESAVKA_UVC_HEIGHT", Some("576"), || {
                with_var("LESAVKA_UVC_FPS", Some("12"), || {
                    let cfg = update_camera_config();
                    assert_eq!(cfg.output, CameraOutput::Uvc);
                    assert_eq!(cfg.codec, CameraCodec::Hevc);
                    assert_eq!(cfg.width, 1024);
                    assert_eq!(cfg.height, 576);
                    assert_eq!(cfg.fps, 12);
                });
            });
        });
    });
}

#[test]
#[serial]
fn camera_config_defaults_when_uvc_dimensions_and_rate_are_missing() {
    with_var("LESAVKA_CAM_OUTPUT", Some("uvc"), || {
        with_var("LESAVKA_UVC_WIDTH", None::<&str>, || {
            with_var("LESAVKA_UVC_HEIGHT", None::<&str>, || {
                with_var("LESAVKA_UVC_FPS", None::<&str>, || {
                    with_var("LESAVKA_UVC_INTERVAL", None::<&str>, || {
                        let cfg = update_camera_config();
                        assert_eq!(cfg.output, CameraOutput::Uvc);
                        assert_eq!(cfg.codec, CameraCodec::Hevc);
                        assert_eq!(cfg.width, 1280);
                        assert_eq!(cfg.height, 720);
                        assert_eq!(cfg.fps, 30);
                    });
                });
            });
        });
    });
}

#[test]
#[serial]
fn camera_config_prefers_explicit_fps_over_interval() {
    with_var("LESAVKA_CAM_OUTPUT", Some("uvc"), || {
        with_var("LESAVKA_UVC_WIDTH", Some("800"), || {
            with_var("LESAVKA_UVC_HEIGHT", Some("600"), || {
                with_var("LESAVKA_UVC_FPS", Some("48"), || {
                    with_var("LESAVKA_UVC_INTERVAL", Some("250000"), || {
                        let cfg = update_camera_config();
                        assert_eq!(cfg.output, CameraOutput::Uvc);
                        assert_eq!(cfg.codec, CameraCodec::Hevc);
                        assert_eq!(cfg.width, 800);
                        assert_eq!(cfg.height, 600);
                        assert_eq!(cfg.fps, 48);
                    });
                });
            });
        });
    });
}

#[test]
#[serial]
fn camera_config_invalid_output_falls_back_to_detected_policy() {
    with_var("LESAVKA_CAM_OUTPUT", Some("not-a-real-mode"), || {
        let cfg = update_camera_config();
        match cfg.output {
            CameraOutput::Uvc => {
                assert_eq!(cfg.codec, CameraCodec::Hevc);
                assert!(cfg.fps > 0);
            }
            CameraOutput::Hdmi => {
                assert!(matches!(cfg.codec, CameraCodec::Mjpeg | CameraCodec::H264));
                assert_eq!(cfg.fps, 30);
            }
        }
    });
}
