#[cfg(not(coverage))]
fn upstream_stale_drop_budget() -> Duration {
    let drop_ms = std::env::var("LESAVKA_UPSTREAM_STALE_DROP_MS")
        .ok()
        .and_then(|value| value.trim().parse::<u64>().ok())
        .unwrap_or(80);
    Duration::from_millis(drop_ms)
}

#[cfg(not(coverage))]
/// Keeps only the newest webcam packet when the host path is already behind.
fn retain_freshest_video_packet(
    pending: &mut std::collections::VecDeque<VideoPacket>,
) -> usize {
    if pending.len() <= 1 {
        return 0;
    }
    let newest = pending.pop_back().expect("non-empty pending video queue");
    let dropped = pending.len();
    pending.clear();
    pending.push_back(newest);
    dropped
}

#[cfg(not(coverage))]
/// Keeps `enqueue_pending_upstream_video_packet` explicit because it sits on relay RPC orchestration, where hardware failures must surface without stopping the server.
/// Inputs are the typed parameters; output is the return value or side effect.
fn enqueue_pending_upstream_video_packet(
    runtime: &UpstreamMediaRuntime,
    pending: &mut std::collections::VecDeque<VideoPacket>,
    pkt: VideoPacket,
    rpc_id: u64,
    session_id: u64,
    camera_session_id: u64,
    context: &'static str,
) {
    runtime.record_client_timing(UpstreamMediaKind::Camera, video_client_timing(&pkt));
    pending.push_back(pkt);
    let coalesced = retain_freshest_video_packet(pending);
    if coalesced > 0 {
        tracing::debug!(
            rpc_id,
            session_id,
            camera_session_id,
            dropped = coalesced,
            context,
            "🎥 coalesced stale upstream video backlog down to the freshest frame"
        );
    }
}

#[cfg(not(coverage))]
const AUDIO_PENDING_LIVE_WINDOW_PACKETS: usize = 8;

#[cfg(not(coverage))]
/// Keeps a tiny newest microphone window so playout can stay smooth without
/// draining old audio.
fn retain_freshest_audio_packet(
    pending: &mut std::collections::VecDeque<AudioPacket>,
) -> usize {
    if pending.len() <= AUDIO_PENDING_LIVE_WINDOW_PACKETS {
        return 0;
    }
    let dropped = pending.len() - AUDIO_PENDING_LIVE_WINDOW_PACKETS;
    pending.drain(..dropped);
    dropped
}

/// Extract client-side timing facts from an upstream microphone packet.
fn audio_client_timing(pkt: &AudioPacket) -> UpstreamClientTiming {
    let capture_pts_us = if pkt.client_capture_pts_us == 0 {
        pkt.pts
    } else {
        pkt.client_capture_pts_us
    };
    let send_pts_us = if pkt.client_send_pts_us == 0 {
        capture_pts_us
    } else {
        pkt.client_send_pts_us
    };
    UpstreamClientTiming {
        capture_pts_us,
        send_pts_us,
        queue_depth: pkt.client_queue_depth,
        queue_age_ms: pkt.client_queue_age_ms,
    }
}

/// Extract client-side timing facts from an upstream camera packet.
fn video_client_timing(pkt: &VideoPacket) -> UpstreamClientTiming {
    let capture_pts_us = if pkt.client_capture_pts_us == 0 {
        pkt.pts
    } else {
        pkt.client_capture_pts_us
    };
    let send_pts_us = if pkt.client_send_pts_us == 0 {
        capture_pts_us
    } else {
        pkt.client_send_pts_us
    };
    UpstreamClientTiming {
        capture_pts_us,
        send_pts_us,
        queue_depth: pkt.client_queue_depth,
        queue_age_ms: pkt.client_queue_age_ms,
    }
}

#[cfg(not(coverage))]
#[derive(Clone, Copy, Debug)]
enum UpstreamStreamCleanupKind {
    Microphone,
    Camera,
}

#[cfg(not(coverage))]
struct UpstreamStreamCleanup {
    runtime: Arc<UpstreamMediaRuntime>,
    kind: UpstreamStreamCleanupKind,
    generation: u64,
    rpc_id: u64,
    session_id: u64,
    camera_session_id: Option<u64>,
    outcome: &'static str,
}

#[cfg(not(coverage))]
impl UpstreamStreamCleanup {
    fn microphone(
        runtime: Arc<UpstreamMediaRuntime>,
        generation: u64,
        rpc_id: u64,
        session_id: u64,
    ) -> Self {
        Self {
            runtime,
            kind: UpstreamStreamCleanupKind::Microphone,
            generation,
            rpc_id,
            session_id,
            camera_session_id: None,
            outcome: "aborted",
        }
    }

    fn camera(
        runtime: Arc<UpstreamMediaRuntime>,
        generation: u64,
        rpc_id: u64,
        session_id: u64,
        camera_session_id: u64,
    ) -> Self {
        Self {
            runtime,
            kind: UpstreamStreamCleanupKind::Camera,
            generation,
            rpc_id,
            session_id,
            camera_session_id: Some(camera_session_id),
            outcome: "aborted",
        }
    }

    fn mark_closed(&mut self) {
        self.outcome = "closed";
    }

    fn mark_superseded(&mut self) {
        self.outcome = "superseded";
    }

    fn mark_aborted(&mut self) {
        self.outcome = "aborted";
    }
}

#[cfg(not(coverage))]
impl Drop for UpstreamStreamCleanup {
    /// Closes only the stream generation owned by this RPC lifecycle guard.
    fn drop(&mut self) {
        match self.kind {
            UpstreamStreamCleanupKind::Microphone => {
                self.runtime.close_microphone(self.generation);
                info!(
                    rpc_id = self.rpc_id,
                    session_id = self.session_id,
                    generation = self.generation,
                    outcome = self.outcome,
                    "🎤 stream_microphone lifecycle ended"
                );
            }
            UpstreamStreamCleanupKind::Camera => {
                self.runtime.close_camera(self.generation);
                info!(
                    rpc_id = self.rpc_id,
                    session_id = self.session_id,
                    camera_session_id = self.camera_session_id.unwrap_or_default(),
                    generation = self.generation,
                    outcome = self.outcome,
                    "🎥 stream_camera lifecycle ended"
                );
            }
        }
    }
}

/// Maps expected remote-audio availability failures onto retryable gRPC status codes.
fn remote_audio_status(message: String) -> Status {
    if message.contains("remote USB gadget is not attached") {
        Status::unavailable(message)
    } else {
        Status::internal(message)
    }
}
