#[derive(Clone)]
pub struct SummaryWidgets {
    pub relay_light: gtk::Box,
    pub relay_value: gtk::Label,
    pub routing_light: gtk::Box,
    pub routing_value: gtk::Label,
    pub gpio_light: gtk::Box,
    pub gpio_value: gtk::Label,
    pub left_eye_light: gtk::Box,
    pub left_eye_value: gtk::Label,
    pub right_eye_light: gtk::Box,
    pub right_eye_value: gtk::Label,
    pub usb_light: gtk::Box,
    pub usb_value: gtk::Label,
    pub uac_light: gtk::Box,
    pub uac_value: gtk::Label,
    pub uvc_light: gtk::Box,
    pub uvc_value: gtk::Label,
    pub upstream_lag_light: gtk::Box,
    pub upstream_lag_value: gtk::Label,
    pub shortcut_value: gtk::Label,
}

#[derive(Clone)]
pub struct DisplayPaneWidgets {
    pub root: gtk::Box,
    pub stack: gtk::Stack,
    pub preview_frame: gtk::AspectFrame,
    pub picture: gtk::Picture,
    pub stream_status: gtk::Label,
    pub preview_placeholder: gtk::Picture,
    pub feed_source_combo: gtk::ComboBoxText,
    pub capture_resolution_combo: gtk::ComboBoxText,
    pub breakout_combo: gtk::ComboBoxText,
    pub clip_button: gtk::Button,
    pub record_button: gtk::Button,
    #[allow(dead_code)]
    pub record_audio_button: gtk::Button,
    pub save_button: gtk::Button,
    pub action_button: gtk::Button,
    pub preview_binding: Rc<RefCell<Option<PreviewBinding>>>,
    pub title: String,
}

pub struct PopoutWindowHandle {
    pub window: gtk::ApplicationWindow,
    pub root: gtk::Box,
    pub frame: gtk::AspectFrame,
    pub picture: gtk::Picture,
    pub status_label: gtk::Label,
    pub binding: PreviewBinding,
}

/// Minimum severity for relay log lines shown in the session console.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum ConsoleLogLevel {
    Error,
    #[default]
    Warn,
    Info,
    Debug,
    Trace,
}

impl ConsoleLogLevel {
    pub const ALL: [Self; 5] = [
        Self::Error,
        Self::Warn,
        Self::Info,
        Self::Debug,
        Self::Trace,
    ];

    /// Stable value stored on the GTK combo row.
    #[must_use]
    pub const fn id(self) -> &'static str {
        match self {
            Self::Error => "error",
            Self::Warn => "warn",
            Self::Info => "info",
            Self::Debug => "debug",
            Self::Trace => "trace",
        }
    }

    /// Short label displayed in the launcher dropdown.
    #[must_use]
    pub const fn label(self) -> &'static str {
        match self {
            Self::Error => "Error",
            Self::Warn => "Warn",
            Self::Info => "Info",
            Self::Debug => "Debug",
            Self::Trace => "Trace",
        }
    }

    /// Parses a GTK combo id back into a log level.
    #[must_use]
    pub fn from_id(raw: &str) -> Option<Self> {
        match raw {
            "error" => Some(Self::Error),
            "warn" => Some(Self::Warn),
            "info" => Some(Self::Info),
            "debug" => Some(Self::Debug),
            "trace" => Some(Self::Trace),
            _ => None,
        }
    }

    /// Numeric ordering where lower values are more important.
    #[must_use]
    pub const fn rank(self) -> u8 {
        match self {
            Self::Error => 0,
            Self::Warn => 1,
            Self::Info => 2,
            Self::Debug => 3,
            Self::Trace => 4,
        }
    }
}

#[derive(Clone)]
pub struct LauncherWidgets {
    pub status_label: gtk::Label,
    pub diagnostics_log: Rc<RefCell<DiagnosticsLog>>,
    pub diagnostics_label: gtk::Label,
    pub diagnostics_scroll: gtk::ScrolledWindow,
    pub diagnostics_popout_label: Rc<RefCell<Option<gtk::Label>>>,
    pub diagnostics_popout_scroll: Rc<RefCell<Option<gtk::ScrolledWindow>>>,
    pub diagnostics_rendered_text: Rc<RefCell<String>>,
    pub session_log_buffer: gtk::TextBuffer,
    pub session_log_view: gtk::TextView,
    pub summary: SummaryWidgets,
    pub power_detail: gtk::Label,
    pub audio_check_detail: gtk::Label,
    pub audio_check_meter: gtk::ProgressBar,
    pub display_panes: [DisplayPaneWidgets; 2],
    pub server_entry: gtk::Entry,
    pub start_button: gtk::Button,
    pub certs_button: gtk::Button,
    pub camera_combo: gtk::ComboBoxText,
    pub camera_quality_combo: gtk::ComboBoxText,
    pub microphone_combo: gtk::ComboBoxText,
    pub speaker_combo: gtk::ComboBoxText,
    pub keyboard_combo: gtk::ComboBoxText,
    pub mouse_combo: gtk::ComboBoxText,
    pub camera_channel_toggle: gtk::ToggleButton,
    pub microphone_channel_toggle: gtk::ToggleButton,
    pub noise_suppression_toggle: gtk::ToggleButton,
    pub audio_channel_toggle: gtk::ToggleButton,
    pub power_auto_button: gtk::Button,
    pub power_on_button: gtk::Button,
    pub power_off_button: gtk::Button,
    pub audio_gain_scale: gtk::Scale,
    pub audio_gain_value: gtk::Label,
    pub mic_gain_scale: gtk::Scale,
    pub mic_gain_value: gtk::Label,
    pub input_toggle_button: gtk::Button,
    pub clipboard_button: gtk::Button,
    pub wake_combo: gtk::ComboBoxText,
    pub usb_recover_button: gtk::Button,
    pub uac_recover_button: gtk::Button,
    pub uvc_recover_button: gtk::Button,
    pub calibration_default_button: gtk::Button,
    pub calibration_factory_button: gtk::Button,
    pub calibration_blind_button: gtk::Button,
    pub calibration_minus_button: gtk::Button,
    pub calibration_plus_button: gtk::Button,
    pub calibration_rig_button: gtk::Button,
    pub device_refresh_button: gtk::Button,
    pub swap_key_button: gtk::Button,
    pub camera_test_button: gtk::Button,
    pub camera_preview_stack: gtk::Stack,
    pub webcam_transport_combo: gtk::ComboBoxText,
    pub webcam_transport_syncing: Rc<Cell<bool>>,
    pub upstream_audio_transport_combo: gtk::ComboBoxText,
    pub upstream_audio_transport_syncing: Rc<Cell<bool>>,
    pub camera_mirror_button: gtk::ToggleButton,
    pub camera_mirror_revealer: gtk::Revealer,
    pub microphone_test_button: gtk::Button,
    pub microphone_replay_button: gtk::Button,
    pub speaker_test_button: gtk::Button,
    pub diagnostics_copy_button: gtk::Button,
    pub diagnostics_popout_button: gtk::Button,
    pub console_copy_button: gtk::Button,
    pub console_popout_button: gtk::Button,
    pub console_level_combo: gtk::ComboBoxText,
    pub session_log_level: Rc<RefCell<ConsoleLogLevel>>,
}

/// Runtime handles the GTK layout contract tests read directly.
#[derive(Clone)]
#[allow(dead_code)]
pub struct DeviceStageWidgets {
    pub devices_panel: gtk::Box,
    pub preview_panel: gtk::Box,
    pub camera_preview_stack: gtk::Stack,
    pub camera_preview_frame: gtk::AspectFrame,
    pub camera_preview: gtk::Picture,
    pub webcam_transport_combo: gtk::ComboBoxText,
    pub upstream_audio_transport_combo: gtk::ComboBoxText,
    pub camera_mirror_button: gtk::ToggleButton,
    pub camera_status: gtk::Label,
}

pub struct LauncherView {
    pub window: gtk::ApplicationWindow,
    pub server_entry: gtk::Entry,
    pub camera_combo: gtk::ComboBoxText,
    pub camera_quality_combo: gtk::ComboBoxText,
    pub microphone_combo: gtk::ComboBoxText,
    pub speaker_combo: gtk::ComboBoxText,
    pub keyboard_combo: gtk::ComboBoxText,
    pub mouse_combo: gtk::ComboBoxText,
    pub device_stage: DeviceStageWidgets,
    pub widgets: LauncherWidgets,
    pub preview: Option<Rc<LauncherPreview>>,
    pub popouts: Rc<RefCell<[Option<PopoutWindowHandle>; 2]>>,
    pub diagnostics_popout: Rc<RefCell<Option<gtk::ApplicationWindow>>>,
    pub log_popout: Rc<RefCell<Option<gtk::ApplicationWindow>>>,
}

pub const LESAVKA_ICON_NAME: &str = "dev.lesavka.launcher";
const LESAVKA_ICON_SEARCH_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/assets/icons");
const LAUNCHER_DEFAULT_WIDTH: i32 = 1540;
const LAUNCHER_DEFAULT_HEIGHT: i32 = 880;
const OPERATIONS_RAIL_WIDTH: i32 = 276;
const RELAY_SUBGROUP_LABEL_WIDTH: i32 = 8;
const DEVICE_STAGING_PANEL_WIDTH: i32 = 512;
const CAMERA_PREVIEW_VIEWPORT_HEIGHT: i32 = 270;
const CAMERA_PREVIEW_VIEWPORT_WIDTH: i32 = 480;
const EYE_PREVIEW_MIN_HEIGHT: i32 = 299;
const EYE_PREVIEW_MIN_WIDTH: i32 = 512;
const SIDE_LOG_MIN_HEIGHT: i32 = 124;
const SIDE_LOG_RECOVERY_BUDGET_SPLIT: i32 = 102;
const SIDE_LOG_RECOVERY_MIN_HEIGHT: i32 = SIDE_LOG_MIN_HEIGHT - SIDE_LOG_RECOVERY_BUDGET_SPLIT;
