/// Choose the pre-encoder webcam format path.
///
/// V4L2 webcams often expose 720p/30 as MJPEG only, so the default accepts
/// either raw frames or MJPEG unless the operator explicitly pins a format.
fn camera_source_profile(allow_v4l2_auto_decode: bool) -> CameraSourceProfile {
    if !allow_v4l2_auto_decode {
        return CameraSourceProfile::Raw;
    }
    if std::env::var("LESAVKA_CAM_MJPG").is_ok() {
        return CameraSourceProfile::Mjpeg;
    }
    match std::env::var("LESAVKA_CAM_FORMAT")
        .ok()
        .as_deref()
        .map(str::trim)
        .map(str::to_ascii_lowercase)
        .as_deref()
    {
        Some("mjpg" | "mjpeg" | "jpeg") => CameraSourceProfile::Mjpeg,
        Some("raw" | "yuyv" | "yuy2") => CameraSourceProfile::Raw,
        _ => CameraSourceProfile::AutoDecode,
    }
}

/// Build the source-to-raw-video chain consumed by the encoder and preview tap.
fn camera_raw_source_chain(
    src_desc: &str,
    src_caps: &str,
    width: u32,
    height: u32,
    fps: u32,
    profile: CameraSourceProfile,
) -> String {
    match profile {
        CameraSourceProfile::Raw => format!("{src_desc} ! {src_caps}"),
        CameraSourceProfile::Mjpeg => format!(
            "{src_desc} ! \
             image/jpeg,width={width},height={height},framerate={fps}/1 ! \
             jpegdec ! videoconvert ! videoscale ! videorate ! \
             video/x-raw,width={width},height={height},framerate={fps}/1"
        ),
        CameraSourceProfile::AutoDecode => format!(
            "{src_desc} ! \
             capsfilter caps=\"{}\" ! \
             decodebin ! videoconvert ! videoscale ! videorate ! \
             video/x-raw,width={width},height={height},framerate={fps}/1,pixel-aspect-ratio=1/1",
            camera_auto_decode_caps(width, height, fps)
        ),
    }
}

/// Caps string that lets decodebin negotiate either raw webcam frames or MJPEG.
fn camera_auto_decode_caps(width: u32, height: u32, fps: u32) -> String {
    format!(
        "video/x-raw,width=(int){width},height=(int){height},framerate=(fraction){fps}/1;image/jpeg,width=(int){width},height=(int){height},framerate=(fraction){fps}/1"
    )
}

/// Convert local webcam frames into the exact outbound UVC profile.
fn camera_output_raw_chain(width: u32, height: u32, fps: u32) -> String {
    format!(
        "videoconvert ! videoscale ! videorate ! \
         video/x-raw,width={width},height={height},framerate={fps}/1,pixel-aspect-ratio=1/1"
    )
}

fn camera_preview_tap_path() -> Option<PathBuf> {
    std::env::var(CAMERA_PREVIEW_TAP_ENV)
        .ok()
        .map(|value| value.trim().to_string())
        .filter(|value| !value.is_empty())
        .map(PathBuf::from)
}

fn camera_preview_tap_branch(width: u32, height: u32, fps: u32) -> String {
    let preview_width = width.clamp(1, i32::MAX as u32);
    let preview_height = height.clamp(1, i32::MAX as u32);
    let preview_fps = fps.clamp(1, 60);
    format!(
        "videoconvert ! videoscale ! videorate ! \
         video/x-raw,format=RGBA,width={preview_width},height={preview_height},framerate={preview_fps}/1,pixel-aspect-ratio=1/1 ! \
         appsink name=preview_sink emit-signals=false sync=false max-buffers=1 drop=true"
    )
}
