use serde::{Deserialize, Serialize};
use std::collections::VecDeque;
use std::fmt::Write as _;

use crate::uplink_telemetry::UpstreamStreamTelemetry;

use super::{
    devices::CameraMode,
    state::{CaptureSizeChoice, FeedSourcePreset, InputRouting, LauncherState, ViewMode},
};

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PerformanceSample {
    pub rtt_ms: f32,
    pub probe_spread_ms: f32,
    pub input_latency_ms: f32,
    pub probe_loss_pct: f32,
    pub client_process_cpu_pct: f32,
    pub server_process_cpu_pct: f32,
    pub video_loss_pct: f32,
    pub left_receive_fps: f32,
    pub left_present_fps: f32,
    pub left_server_fps: f32,
    pub left_stream_spread_ms: f32,
    pub left_packet_gap_peak_ms: f32,
    pub left_present_gap_peak_ms: f32,
    pub left_queue_depth: u32,
    pub left_queue_peak: u32,
    pub left_server_source_gap_peak_ms: f32,
    pub left_server_send_gap_peak_ms: f32,
    pub left_server_queue_peak: u32,
    pub left_server_encoder_label: String,
    pub left_decoder_label: String,
    pub left_stream_caps_label: String,
    pub left_decoded_caps_label: String,
    pub left_rendered_caps_label: String,
    pub right_receive_fps: f32,
    pub right_present_fps: f32,
    pub right_server_fps: f32,
    pub right_stream_spread_ms: f32,
    pub right_packet_gap_peak_ms: f32,
    pub right_present_gap_peak_ms: f32,
    pub right_queue_depth: u32,
    pub right_queue_peak: u32,
    pub right_server_source_gap_peak_ms: f32,
    pub right_server_send_gap_peak_ms: f32,
    pub right_server_queue_peak: u32,
    pub right_server_encoder_label: String,
    pub right_decoder_label: String,
    pub right_stream_caps_label: String,
    pub right_decoded_caps_label: String,
    pub right_rendered_caps_label: String,
    pub upstream_camera: UpstreamStreamTelemetry,
    pub upstream_microphone: UpstreamStreamTelemetry,
    pub upstream_mode: String,
    pub dropped_frames: u64,
    pub queue_depth: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiagnosticsLog {
    capacity: usize,
    history: VecDeque<PerformanceSample>,
}

impl DiagnosticsLog {
    pub fn new(capacity: usize) -> Self {
        let capacity = capacity.max(1);
        Self {
            capacity,
            history: VecDeque::with_capacity(capacity),
        }
    }

    pub fn record(&mut self, sample: PerformanceSample) {
        if self.history.len() == self.capacity {
            let _ = self.history.pop_front();
        }
        self.history.push_back(sample);
    }

    pub fn latest(&self) -> Option<&PerformanceSample> {
        self.history.back()
    }

    pub fn len(&self) -> usize {
        self.history.len()
    }

    pub fn is_empty(&self) -> bool {
        self.history.is_empty()
    }

    pub fn iter(&self) -> impl Iterator<Item = &PerformanceSample> {
        self.history.iter()
    }
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct MediaChannelState {
    pub camera: bool,
    pub microphone: bool,
    pub audio: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SnapshotReport {
    pub client_version: String,
    pub server_version: Option<String>,
    pub server_available: bool,
    pub routing: InputRouting,
    pub view_mode: ViewMode,
    pub remote_active: bool,
    pub power_state: String,
    pub client_process_cpu_pct: f32,
    pub server_process_cpu_pct: f32,
    pub preview_source: String,
    pub client_display_limit: String,
    pub left_surface: String,
    pub left_feed_source: String,
    pub left_capture_profile: String,
    pub left_capture_transport: String,
    pub left_breakout_profile: String,
    pub left_decoder_label: String,
    pub left_stream_spread_ms: f32,
    pub left_packet_gap_peak_ms: f32,
    pub left_present_gap_peak_ms: f32,
    pub left_queue_depth: u32,
    pub left_queue_peak: u32,
    pub left_server_source_gap_peak_ms: f32,
    pub left_server_send_gap_peak_ms: f32,
    pub left_server_queue_peak: u32,
    pub left_server_encoder_label: String,
    pub left_stream_caps_label: String,
    pub left_decoded_caps_label: String,
    pub left_rendered_caps_label: String,
    pub right_surface: String,
    pub right_feed_source: String,
    pub right_capture_profile: String,
    pub right_capture_transport: String,
    pub right_breakout_profile: String,
    pub right_decoder_label: String,
    pub right_stream_spread_ms: f32,
    pub right_packet_gap_peak_ms: f32,
    pub right_present_gap_peak_ms: f32,
    pub right_queue_depth: u32,
    pub right_queue_peak: u32,
    pub right_server_source_gap_peak_ms: f32,
    pub right_server_send_gap_peak_ms: f32,
    pub right_server_queue_peak: u32,
    pub right_server_encoder_label: String,
    pub right_stream_caps_label: String,
    pub right_decoded_caps_label: String,
    pub right_rendered_caps_label: String,
    pub selected_camera: Option<String>,
    pub camera_quality_label: String,
    pub upstream_camera_transport: String,
    pub selected_microphone: Option<String>,
    pub selected_speaker: Option<String>,
    pub media_channels: MediaChannelState,
    pub audio_gain_label: String,
    pub mic_gain_label: String,
    pub upstream_camera: UpstreamStreamTelemetry,
    pub upstream_microphone: UpstreamStreamTelemetry,
    pub upstream_mode: String,
    pub av_delivery_skew_ms: f32,
    pub av_enqueue_skew_ms: f32,
    pub av_sync_health: String,
    pub planner_available: bool,
    pub planner_phase: String,
    pub planner_session_id: u64,
    pub planner_live_lag_ms: Option<f32>,
    pub planner_skew_ms: Option<f32>,
    pub planner_stale_audio_drops: u64,
    pub planner_stale_video_drops: u64,
    pub planner_skew_video_drops: u64,
    pub planner_freshness_reanchors: u64,
    pub planner_startup_timeouts: u64,
    pub planner_video_freezes: u64,
    pub planner_detail: String,
    pub calibration_available: bool,
    pub calibration_profile: String,
    pub calibration_source: String,
    pub calibration_confidence: String,
    pub calibration_detail: String,
    pub calibration_updated_at: String,
    pub factory_audio_offset_us: i64,
    pub factory_video_offset_us: i64,
    pub default_audio_offset_us: i64,
    pub default_video_offset_us: i64,
    pub active_audio_offset_us: i64,
    pub active_video_offset_us: i64,
    pub selected_keyboard: Option<String>,
    pub selected_mouse: Option<String>,
    pub status: String,
    pub recent_samples: Vec<PerformanceSample>,
    pub notes: Vec<String>,
    pub recommendations: Vec<String>,
    pub probe_command: String,
}
