#[path = "status_details/popout_windows.rs"]
mod status_details_popout_windows;
use status_details_popout_windows::{
    apply_popout_window_geometry, install_popout_drag, schedule_popout_window_geometry,
};
pub use status_details_popout_windows::present_popout_windows;

pub fn gpio_power_label(power: &CapturePowerStatus) -> String {
    if power.available && power.enabled {
        "On".to_string()
    } else {
        "Off".to_string()
    }
}

pub fn capture_power_detail(power: &CapturePowerStatus) -> String {
    if !power.available {
        return format!("{} is unavailable: {}", power.unit, power.detail);
    }
    let detected = if power.enabled {
        format!(" • {}", gpio_detection_detail(power.detected_devices))
    } else {
        String::new()
    };
    match power.mode.as_str() {
        "forced-on" => format!(
            "{} • awake • {}{} • leases {}",
            power.unit, power.detail, detected, power.active_leases
        ),
        "forced-off" => format!(
            "{} • dark • {}{} • leases {}",
            power.unit, power.detail, detected, power.active_leases
        ),
        _ => format!(
            "{} • auto • {}{} • leases {}",
            power.unit, power.detail, detected, power.active_leases
        ),
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum StatusLightState {
    Idle,
    Live,
    Connected,
    Warning,
    Caution,
}

impl StatusLightState {
    fn from_active(active: bool) -> Self {
        if active { Self::Live } else { Self::Idle }
    }

    fn css_class(self) -> &'static str {
        match self {
            Self::Idle => "status-light-idle",
            Self::Live => "status-light-live",
            Self::Connected => "status-light-connected",
            Self::Warning => "status-light-warning",
            Self::Caution => "status-light-caution",
        }
    }
}

fn server_light_state(state: &LauncherState, relay_live: bool) -> StatusLightState {
    if !state.server_available || !server_version_known(state) {
        StatusLightState::Idle
    } else if server_versions_match(state) {
        if relay_live {
            StatusLightState::Connected
        } else {
            StatusLightState::Live
        }
    } else if relay_live {
        StatusLightState::Caution
    } else {
        StatusLightState::Warning
    }
}

/// Confirms the server reported a usable version before claiming compatibility.
fn server_version_known(state: &LauncherState) -> bool {
    state
        .server_version
        .as_deref()
        .map(normalize_version)
        .is_some_and(|version| !version.is_empty())
}

/// Compares the reachable server version against this client build.
fn server_versions_match(state: &LauncherState) -> bool {
    state
        .server_version
        .as_deref()
        .map(normalize_version)
        .is_some_and(|server_version| server_version == normalize_version(crate::VERSION))
}

/// Compares versions independent of whether the source included a leading `v`.
fn normalize_version(version: &str) -> &str {
    version.trim().trim_start_matches('v')
}

/// Show the connected server version, or an explicit unknown marker when disconnected.
fn server_version_label(state: &LauncherState) -> String {
    if !state.server_available {
        return "???".to_string();
    }
    let version = state
        .server_version
        .as_deref()
        .map(str::trim)
        .filter(|version| !version.is_empty());
    match version {
        Some(version) if version.starts_with('v') => version.to_string(),
        Some(version) => format!("v{version}"),
        None => "???".to_string(),
    }
}

/// Summarize whether the composite USB gadget appears reachable to the host.
fn recovery_usb_health(state: &LauncherState, relay_live: bool) -> (StatusLightState, String) {
    if !state.server_available {
        return (StatusLightState::Idle, "Offline".to_string());
    }
    if matches!(state.server_camera_output.as_deref(), Some("uvc")) {
        return (StatusLightState::Live, "Enumerated".to_string());
    }
    if let Some(output) = state.server_camera_output.as_deref() {
        return (StatusLightState::Warning, output.to_ascii_uppercase());
    }
    if state.server_camera.is_none() && state.server_microphone.is_none() {
        if relay_live {
            return (StatusLightState::Live, "Connected".to_string());
        }
        return (StatusLightState::Caution, "Unknown".to_string());
    }
    if state.server_camera == Some(false) && state.server_microphone == Some(false) {
        return (StatusLightState::Warning, "Missing".to_string());
    }
    (StatusLightState::Caution, "Partial".to_string())
}

/// Summarize whether the UAC microphone/audio function is advertised by the relay.
fn recovery_uac_health(
    state: &LauncherState,
    relay_live: bool,
    stream: Option<&crate::uplink_telemetry::UpstreamStreamTelemetry>,
) -> (StatusLightState, String) {
    if !state.server_available {
        return (StatusLightState::Idle, "Offline".to_string());
    }
    let codec = state.upstream_audio_transport.label().to_string();
    if state.server_microphone == Some(false) {
        return (StatusLightState::Warning, "Missing".to_string());
    }
    if state.server_microphone.is_none() {
        if relay_live {
            if !state.channels.microphone {
                return (StatusLightState::Idle, "Paused".to_string());
            }
            let (health, label) = media_stream_health(stream, MediaStreamKind::Microphone);
            if matches!(health, StatusLightState::Live) {
                return (health, codec);
            }
            return (health, label);
        }
        return (StatusLightState::Caution, "Unknown".to_string());
    }
    if !relay_live {
        return (StatusLightState::Live, codec);
    }
    if !state.channels.microphone {
        return (StatusLightState::Idle, "Paused".to_string());
    }
    let (health, label) = media_stream_health(stream, MediaStreamKind::Microphone);
    if matches!(health, StatusLightState::Live) {
        (health, codec)
    } else {
        (health, label)
    }
}

/// Summarize whether the UVC camera function is advertised with the selected upstream codec.
fn recovery_uvc_health(
    state: &LauncherState,
    relay_live: bool,
    stream: Option<&crate::uplink_telemetry::UpstreamStreamTelemetry>,
) -> (StatusLightState, String) {
    if !state.server_available {
        return (StatusLightState::Idle, "Offline".to_string());
    }
    let codec = state.effective_webcam_transport().label().to_string();
    if state.server_camera == Some(false) {
        return (StatusLightState::Warning, "Missing".to_string());
    }
    if state.server_camera.is_none() {
        if relay_live {
            if !state.channels.camera {
                return (StatusLightState::Idle, "Paused".to_string());
            }
            let (health, label) = media_stream_health(stream, MediaStreamKind::Camera);
            if matches!(health, StatusLightState::Live) {
                return (health, codec);
            }
            return (health, label);
        }
        return (StatusLightState::Caution, "Unknown".to_string());
    }
    if !matches!(state.server_camera_output.as_deref(), Some("uvc")) {
        let value = state
            .server_camera_output
            .as_deref()
            .map(|output| format!("{}/{}", output.to_ascii_uppercase(), codec))
            .unwrap_or(codec);
        return (StatusLightState::Caution, value);
    }
    if state.upstream_sync.available {
        match state.upstream_sync.uvc_integrity_status.as_str() {
            "ready" => {}
            "holding" => return (StatusLightState::Caution, "Holding".to_string()),
            "fault" => return (StatusLightState::Warning, "Integrity fault".to_string()),
            _ => return (StatusLightState::Caution, "Unverified".to_string()),
        }
        match state.upstream_sync.uvc_contract_status.as_str() {
            "ready" if !state.upstream_sync.uvc_contract_divergent => {}
            "" | "unavailable" | "unverified" => {
                return (StatusLightState::Caution, "Unverified".to_string());
            }
            _ => return (StatusLightState::Warning, "Contract fault".to_string()),
        }
    }
    if !relay_live {
        return (StatusLightState::Live, codec);
    }
    if !state.channels.camera {
        return (StatusLightState::Idle, "Paused".to_string());
    }
    let (health, label) = media_stream_health(stream, MediaStreamKind::Camera);
    if matches!(health, StatusLightState::Live) {
        (health, codec)
    } else {
        (health, label)
    }
}

#[derive(Clone, Copy)]
enum MediaStreamKind {
    Camera,
    Microphone,
}

/// Converts live uplink telemetry into the small, glanceable UAC/UVC chip state.
fn media_stream_health(
    stream: Option<&crate::uplink_telemetry::UpstreamStreamTelemetry>,
    kind: MediaStreamKind,
) -> (StatusLightState, String) {
    let Some(stream) = stream else {
        return match kind {
            MediaStreamKind::Camera => (StatusLightState::Caution, "No Frames".to_string()),
            MediaStreamKind::Microphone => (StatusLightState::Caution, "No Flow".to_string()),
        };
    };
    if !stream.enabled {
        return (StatusLightState::Idle, "Paused".to_string());
    }
    if !stream.last_error.trim().is_empty() {
        return (StatusLightState::Warning, "Error".to_string());
    }
    if !stream.connected {
        return match kind {
            MediaStreamKind::Camera => (StatusLightState::Caution, "No Frames".to_string()),
            MediaStreamKind::Microphone => (StatusLightState::Caution, "No Flow".to_string()),
        };
    }
    if stream.packets_streamed == 0 {
        let label = if stream.packets_enqueued > 0 {
            "Queued"
        } else {
            match kind {
                MediaStreamKind::Camera => "No Frames",
                MediaStreamKind::Microphone => "No Flow",
            }
        };
        return (StatusLightState::Caution, label.to_string());
    }

    let (delivery_budget_ms, enqueue_budget_ms, queue_pressure, healthy_label) = match kind {
        MediaStreamKind::Camera => (250.0, 250.0, 24, "Frames"),
        MediaStreamKind::Microphone => (180.0, 120.0, 12, "Flowing"),
    };
    if stream.latest_delivery_age_ms > delivery_budget_ms
        || stream.latest_enqueue_age_ms > enqueue_budget_ms
    {
        return (StatusLightState::Caution, "Lagging".to_string());
    }
    if stream.queue_depth >= queue_pressure {
        return (StatusLightState::Caution, "Dropping".to_string());
    }
    (StatusLightState::Live, healthy_label.to_string())
}

/// Summarize the server-side client-capture-to-UVC handoff lag.
fn upstream_lag_health(
    status: &crate::launcher::state::UpstreamSyncStatus,
    relay_live: bool,
) -> (StatusLightState, String, String) {
    if !relay_live {
        return (
            StatusLightState::Idle,
            "Off".to_string(),
            "Relay is not connected.".to_string(),
        );
    }
    if !status.available {
        return (
            StatusLightState::Caution,
            "???".to_string(),
            format!("Upstream lag unavailable: {}", status.detail),
        );
    }
    let Some(lag_ms) = status.live_lag_ms else {
        return (
            StatusLightState::Caution,
            "???".to_string(),
            "No upstream UVC handoff timing sample is available yet.".to_string(),
        );
    };
    let label = compact_lag_label(lag_ms);
    let state = if lag_ms <= 500.0 {
        StatusLightState::Connected
    } else if lag_ms <= 1_000.0 {
        StatusLightState::Live
    } else if lag_ms <= 1_500.0 {
        StatusLightState::Caution
    } else {
        StatusLightState::Warning
    };
    let tooltip = format!(
        "Lesavka upstream lower-bound lag to UVC handoff: {lag_ms:.0} ms. This excludes Google Meet/browser buffering after the RCT receives the virtual webcam."
    );
    (state, label, tooltip)
}

fn compact_lag_label(lag_ms: f32) -> String {
    if lag_ms >= 950.0 {
        format!("{:.1}s", lag_ms / 1_000.0)
    } else {
        format!("{:.0}ms", lag_ms.max(0.0))
    }
}

fn gpio_light_state(power: &CapturePowerStatus) -> StatusLightState {
    StatusLightState::from_active(power.available && power.enabled)
}

fn gpio_detection_detail(detected_devices: u32) -> String {
    match detected_devices {
        0 => "no eyes detected".to_string(),
        1 => "1 eye detected".to_string(),
        count => format!("{count} eyes detected"),
    }
}

#[derive(Clone, Copy)]
enum EyeChipSide {
    Left,
    Right,
}

fn eye_stream_health(
    sample: Option<&crate::launcher::diagnostics::PerformanceSample>,
    side: EyeChipSide,
    relay_live: bool,
) -> (StatusLightState, String, String) {
    if !relay_live {
        return (
            StatusLightState::Idle,
            "Off".to_string(),
            "Relay is not connected.".to_string(),
        );
    }
    let Some(sample) = sample else {
        return (
            StatusLightState::Warning,
            "0 fps".to_string(),
            "No eye telemetry sample is available yet.".to_string(),
        );
    };
    let (receive_fps, present_fps, server_fps, queue_depth, queue_peak, packet_gap, present_gap) =
        match side {
            EyeChipSide::Left => (
                sample.left_receive_fps,
                sample.left_present_fps,
                sample.left_server_fps,
                sample.left_queue_depth,
                sample.left_queue_peak,
                sample.left_packet_gap_peak_ms,
                sample.left_present_gap_peak_ms,
            ),
            EyeChipSide::Right => (
                sample.right_receive_fps,
                sample.right_present_fps,
                sample.right_server_fps,
                sample.right_queue_depth,
                sample.right_queue_peak,
                sample.right_packet_gap_peak_ms,
                sample.right_present_gap_peak_ms,
            ),
        };
    let label = format!("{:.0} fps", present_fps.max(0.0));
    let target_fps = server_fps.max(receive_fps).max(1.0);
    let ratio = (present_fps / target_fps).clamp(0.0, 1.0);
    let has_glitch = sample.video_loss_pct > 0.1
        || sample.dropped_frames > 0
        || queue_depth > 0
        || queue_peak > 2
        || packet_gap > 90.0
        || present_gap > 90.0;
    let state = if present_fps < 1.0 || receive_fps < 1.0 {
        StatusLightState::Warning
    } else if ratio >= 0.98 && !has_glitch {
        StatusLightState::Connected
    } else if ratio >= 0.90 && sample.video_loss_pct < 1.0 {
        StatusLightState::Live
    } else if ratio >= 0.65 {
        StatusLightState::Caution
    } else {
        StatusLightState::Warning
    };
    let tooltip = format!(
        "present={present_fps:.1} fps receive={receive_fps:.1} fps server={server_fps:.1} fps loss={:.1}% dropped={} queue={}/{} gaps={packet_gap:.0}/{present_gap:.0} ms",
        sample.video_loss_pct, sample.dropped_frames, queue_depth, queue_peak
    );
    (state, label, tooltip)
}

/// Highlights the currently active capture mode so it reads like a segmented control.
fn sync_power_mode_button_styles(widgets: &LauncherWidgets, mode: &str) {
    for button in [
        &widgets.power_auto_button,
        &widgets.power_on_button,
        &widgets.power_off_button,
    ] {
        button.remove_css_class("pill-toggle-active");
    }
    match mode {
        "forced-on" => widgets.power_on_button.add_css_class("pill-toggle-active"),
        "forced-off" => widgets.power_off_button.add_css_class("pill-toggle-active"),
        _ => widgets
            .power_auto_button
            .add_css_class("pill-toggle-active"),
    }
}

/// Reports which local staging checks are active right now.
fn local_test_detail(
    camera_running: bool,
    microphone_running: bool,
    speaker_running: bool,
    microphone_replay_running: bool,
) -> String {
    let mut active = Vec::new();
    if camera_running {
        active.push("camera preview");
    }
    if microphone_running {
        active.push("mic monitor");
    }
    if speaker_running {
        active.push("speaker tone");
    }
    if microphone_replay_running {
        active.push("mic replay");
    }

    if active.is_empty() {
        "Local checks are idle. Use Start Preview, Monitor Mic, Replay, or Play Tone before you launch."
            .to_string()
    } else {
        format!(
            "Local checks running: {}. Stop them whenever staging is complete.",
            active.join(", ")
        )
    }
}
