use std::time::Duration;
use tokio::time::Instant;

/// Logical upstream media kinds that share one live-call session timeline.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum UpstreamMediaKind {
    /// Webcam uplink frames destined for the UVC/HDMI sink path.
    Camera,
    /// Microphone uplink packets destined for the UAC sink path.
    Microphone,
}

/// Client-supplied timing facts attached to one upstream media packet.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct UpstreamClientTiming {
    /// Packet capture timestamp on the shared client media clock.
    pub capture_pts_us: u64,
    /// Client media-clock timestamp when the packet entered the async uplink
    /// queue. Stamping at enqueue prevents stream scheduling from posing as
    /// capture skew.
    pub send_pts_us: u64,
    /// Uplink queue depth observed as the packet left the async queue.
    pub queue_depth: u32,
    /// Packet age observed as the packet left the async queue.
    pub queue_age_ms: u32,
}

/// Lease returned when one upstream media stream becomes the active owner.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct UpstreamStreamLease {
    /// Shared session id for the current upstream live-call window.
    pub session_id: u64,
    /// Per-kind generation used to supersede older streams of the same kind.
    pub generation: u64,
}

/// One rebased upstream packet plus its planned server playout time.
#[derive(Clone, Copy, Debug)]
pub struct PlannedUpstreamPacket {
    /// Session-local packet timestamp after rebase onto the shared server clock.
    pub local_pts_us: u64,
    /// Wall-clock deadline when the server should present this packet.
    pub due_at: Instant,
    /// How late the packet already is when planned, if any.
    pub late_by: Duration,
    /// How far this packet's capture time trails the freshest relevant input
    /// frontier known to the planner.
    pub source_lag: Duration,
}

/// Result of asking the shared upstream runtime how to handle one packet.
#[derive(Clone, Copy, Debug)]
pub enum UpstreamPlanDecision {
    /// Hold the packet inside the local stream queue until the pairing window
    /// has enough cross-stream context to assign a trustworthy playout time.
    AwaitingPair,
    /// Discard the packet because it belongs before the shared overlapping A/V
    /// session base and would only reintroduce startup skew.
    DropBeforeOverlap,
    /// Discard a packet that would violate the live freshness or A/V skew
    /// contract.
    DropStale(&'static str),
    /// Stop the stream because paired startup never converged.
    StartupFailed(&'static str),
    /// Present the packet at the planned wall-clock deadline.
    Play(PlannedUpstreamPacket),
}

/// Snapshot of the authoritative upstream sync planner.
#[derive(Clone, Debug)]
pub struct UpstreamPlannerSnapshot {
    pub session_id: u64,
    pub phase: &'static str,
    pub latest_camera_remote_pts_us: Option<u64>,
    pub latest_microphone_remote_pts_us: Option<u64>,
    pub last_video_presented_pts_us: Option<u64>,
    pub last_audio_presented_pts_us: Option<u64>,
    pub live_lag_ms: Option<f64>,
    pub planner_skew_ms: Option<f64>,
    pub stale_audio_drops: u64,
    pub stale_video_drops: u64,
    pub skew_video_drops: u64,
    pub freshness_reanchors: u64,
    pub startup_timeouts: u64,
    pub video_freezes: u64,
    pub last_reason: String,
    pub client_capture_skew_ms: Option<f64>,
    pub client_send_skew_ms: Option<f64>,
    pub server_receive_skew_ms: Option<f64>,
    pub camera_client_queue_age_ms: Option<f64>,
    pub microphone_client_queue_age_ms: Option<f64>,
    pub camera_server_receive_age_ms: Option<f64>,
    pub microphone_server_receive_age_ms: Option<f64>,
    pub client_capture_abs_skew_p95_ms: Option<f64>,
    pub client_send_abs_skew_p95_ms: Option<f64>,
    pub server_receive_abs_skew_p95_ms: Option<f64>,
    pub camera_client_queue_age_p95_ms: Option<f64>,
    pub microphone_client_queue_age_p95_ms: Option<f64>,
    pub sink_handoff_skew_ms: Option<f64>,
    pub sink_handoff_abs_skew_p95_ms: Option<f64>,
    pub camera_sink_late_ms: Option<f64>,
    pub microphone_sink_late_ms: Option<f64>,
    pub camera_sink_late_p95_ms: Option<f64>,
    pub microphone_sink_late_p95_ms: Option<f64>,
    pub client_timing_window_samples: u64,
    pub sink_handoff_window_samples: u64,
}
