// Contract tests for the launcher layout proportions.
//
// Scope: statically guard the GTK layout constants and sizing glue used by
// the launcher shell.
// Targets: split `client/src/launcher/ui_components/*` layout modules.
// Why: the launcher is an operational control surface; accidental spacing
// regressions can hide diagnostics or make eye/device previews unusable.

const UI_LAYOUT_SRC: &str = concat!(
    include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/client/src/launcher/ui.rs"
    )),
    include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/client/src/launcher/ui/startup_window_guard.rs"
    )),
    include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/client/src/launcher/ui_components/types.rs"
    )),
    include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/client/src/launcher/ui_components/build_shell.rs"
    )),
    include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/client/src/launcher/ui/preview_profiles.rs"
    )),
    include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/client/src/launcher/ui_components/display_pane.rs"
    )),
    include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/client/src/launcher/ui_components/build_device_controls.rs"
    )),
    include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/client/src/launcher/ui_components/build_operations_rail.rs"
    )),
    include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/client/src/launcher/ui_components/combo_helpers.rs"
    )),
    include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/client/src/launcher/ui_components/control_buttons.rs"
    )),
    include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/client/src/launcher/ui_components/panel_chips.rs"
    )),
    include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/client/src/launcher/ui_components/style.rs"
    )),
);

fn const_i32(name: &str) -> i32 {
    let needle = format!("const {name}: i32 = ");
    let line = UI_LAYOUT_SRC
        .lines()
        .find(|line| line.trim_start().starts_with(&needle))
        .unwrap_or_else(|| panic!("missing {name} constant"));
    line.trim_start()
        .trim_start_matches(&needle)
        .trim_end_matches(';')
        .parse()
        .unwrap_or_else(|err| panic!("invalid {name} constant: {err}"))
}

fn source_index(needle: &str) -> usize {
    UI_LAYOUT_SRC
        .find(needle)
        .unwrap_or_else(|| panic!("missing source marker: {needle}"))
}

#[test]
fn launcher_default_size_stays_inside_1080p() {
    assert_eq!(const_i32("LAUNCHER_DEFAULT_WIDTH"), 1540);
    assert_eq!(const_i32("LAUNCHER_DEFAULT_HEIGHT"), 880);
    assert!(const_i32("LAUNCHER_DEFAULT_WIDTH") <= 1920);
    assert!(
        const_i32("LAUNCHER_DEFAULT_HEIGHT") <= 960,
        "leave room for desktop panels and window chrome on a 1080p monitor"
    );
    assert!(
        !UI_LAYOUT_SRC
            .contains("window.set_size_request(LAUNCHER_DEFAULT_WIDTH, LAUNCHER_DEFAULT_HEIGHT);"),
        "the top-level window should not pin a larger minimum than the startup budget"
    );
    assert!(UI_LAYOUT_SRC.contains("let max_width = width.saturating_sub(72).max(640) as i32;"));
    assert!(UI_LAYOUT_SRC.contains("let max_height = height.saturating_sub(120).max(520) as i32;"));
    assert!(
        UI_LAYOUT_SRC.contains("(1540.min(max_width), 880.min(max_height))"),
        "the activation path must use the same compact startup budget as the shell"
    );
    assert!(UI_LAYOUT_SRC.contains("schedule_launcher_window_guard(app, &window, launcher_size);"));
    assert!(
        UI_LAYOUT_SRC.contains("guard_window.set_default_size(launcher_size.0, launcher_size.1);")
    );
}

#[test]
fn eye_panes_keep_the_docked_preview_footprint_without_forcing_maximized_width() {
    assert_eq!(const_i32("EYE_PREVIEW_MIN_WIDTH"), 512);
    assert_eq!(const_i32("EYE_PREVIEW_MIN_HEIGHT"), 299);
    assert!(UI_LAYOUT_SRC.contains("display_row.set_vexpand(false);"));
    assert!(UI_LAYOUT_SRC.contains("display_row.set_valign(gtk::Align::Start);"));
    assert!(
        !UI_LAYOUT_SRC.contains("display_row.set_vexpand(true);"),
        "a vertically expanding 16:9 eye row turns extra height into horizontal overflow"
    );
    assert!(UI_LAYOUT_SRC.contains("preview_frame.set_hexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("preview_frame.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("preview_frame.set_halign(gtk::Align::Fill);"));
    assert!(UI_LAYOUT_SRC.contains("preview_box.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("stack.set_vexpand(true);"));
    assert!(
        UI_LAYOUT_SRC.contains("caption_label.set_halign(gtk::Align::End)")
            || UI_LAYOUT_SRC.contains("capture_label.set_halign(gtk::Align::End)")
    );
    assert!(UI_LAYOUT_SRC.contains("capture_label.set_ellipsize(pango::EllipsizeMode::Start);"));
    assert!(!UI_LAYOUT_SRC.contains("root.append(&stream_status);"));
    assert!(UI_LAYOUT_SRC.contains("stream_status.add_css_class(\"eye-inline-status\");"));
    assert!(UI_LAYOUT_SRC.contains("let header_overlay = gtk::Overlay::new();"));
    assert!(UI_LAYOUT_SRC.contains("header_row.append(&title_label);"));
    assert!(UI_LAYOUT_SRC.contains("header_row.append(&capture_label);"));
    assert!(UI_LAYOUT_SRC.contains("header_overlay.add_overlay(&stream_status);"));
    assert!(
        source_index("header_row.append(&title_label);")
            < source_index("header_row.append(&capture_label);")
    );
    assert!(
        source_index("controls_grid.attach(&capture_row, 1, 0, 1, 1);")
            < source_index("controls_grid.attach(&action_button, 2, 0, 1, 1);")
    );
    assert!(
        source_index("controls_grid.attach(&breakout_row, 0, 1, 1, 1);")
            < source_index("controls_grid.attach(&capture_actions, 1, 1, 2, 1);")
    );
    assert!(UI_LAYOUT_SRC.contains("const EYE_CAPTURE_BUTTON_WIDTH: i32 = 54;"));
    assert!(UI_LAYOUT_SRC.contains("let clip_button = gtk::Button::with_label(\"📷\");"));
    assert!(UI_LAYOUT_SRC.contains("let record_button = gtk::Button::with_label(\"⏺\");"));
    assert!(UI_LAYOUT_SRC.contains("record_button.add_css_class(\"media-toggle\");"));
    assert!(UI_LAYOUT_SRC.contains("let record_audio_button = gtk::Button::with_label(\"🔇\");"));
    assert!(UI_LAYOUT_SRC.contains("record_audio_button.add_css_class(\"media-toggle\");"));
    assert!(UI_LAYOUT_SRC.contains("let save_button = gtk::Button::with_label(\"📁\");"));
    assert!(UI_LAYOUT_SRC.contains("let action_button = gtk::Button::with_label(\"↗\");"));
    assert!(UI_LAYOUT_SRC.contains("capture_actions.append(&clip_button);"));
    assert!(
        source_index("capture_actions.append(&record_button);")
            < source_index("capture_actions.append(&record_audio_button);")
    );
    assert!(
        source_index("capture_actions.append(&record_audio_button);")
            < source_index("capture_actions.append(&save_button);")
    );
}

#[test]
fn eye_and_device_combos_use_compact_labels_so_the_rail_stays_visible() {
    assert!(UI_LAYOUT_SRC.contains("fn compact_capture_mode_label("));
    assert!(UI_LAYOUT_SRC.contains("format!(\"{size}@{fps}\")"));
    assert!(UI_LAYOUT_SRC.contains("format!(\"Source {}\", compact_size_label(option.height))"));
    assert!(UI_LAYOUT_SRC.contains("fn install_device_choice_combo_behavior("));
    assert!(UI_LAYOUT_SRC.contains("combo.set_popup_fixed_width(false);"));
    assert!(UI_LAYOUT_SRC.contains("fn combo_active_full_label("));
    assert!(UI_LAYOUT_SRC.contains("Selected: {full}. Open the dropdown for compact choices"));
    assert!(UI_LAYOUT_SRC.contains("const DEVICE_COMBO_BUTTON_LABEL_LIMIT: usize = 18;"));
    assert!(UI_LAYOUT_SRC.contains("append_input_choice(combo, value);"));
    assert!(
        UI_LAYOUT_SRC.contains("shorten_label_with_limit(&label, DEVICE_COMBO_BUTTON_LABEL_LIMIT)")
    );
    assert!(UI_LAYOUT_SRC.contains(
        "shorten_label_with_limit(&stage_choice_label(value), DEVICE_COMBO_BUTTON_LABEL_LIMIT)"
    ));
    assert!(UI_LAYOUT_SRC.contains("hover clipped popup choices to scroll"));
    assert!(UI_LAYOUT_SRC.contains("combobox.device-choice-combo popover row:hover label"));
    assert!(
        !UI_LAYOUT_SRC.contains("@ {} fps (Device H.264)"),
        "long capture labels force a huge GTK combo natural width"
    );
    assert!(!UI_LAYOUT_SRC.contains("(Source Size)"));
    assert!(!UI_LAYOUT_SRC.contains("(Display Size)"));
    assert!(UI_LAYOUT_SRC.contains("combobox.compact-combo"));
    assert!(UI_LAYOUT_SRC.contains("combobox.device-choice-combo"));
    assert!(
        UI_LAYOUT_SRC
            .matches(".add_css_class(\"compact-combo\")")
            .count()
            >= 9,
        "display, media, and input combos should be allowed to shrink"
    );
}

#[test]
fn device_staging_and_testing_stay_independent_so_preview_does_not_fill_dead_height() {
    assert!(UI_LAYOUT_SRC.contains("staging_row.set_homogeneous(false);"));
    assert!(UI_LAYOUT_SRC.contains("staging_row.set_vexpand(false);"));
    assert_eq!(const_i32("DEVICE_STAGING_PANEL_WIDTH"), 512);
    assert!(UI_LAYOUT_SRC.contains("devices_panel.set_hexpand(false);"));
    assert!(
        UI_LAYOUT_SRC.contains("devices_panel.set_size_request(DEVICE_STAGING_PANEL_WIDTH, -1);")
    );
    assert!(UI_LAYOUT_SRC.contains("devices_panel.set_valign(gtk::Align::Fill);"));
    assert!(UI_LAYOUT_SRC.contains("preview_panel.set_valign(gtk::Align::Fill);"));
    assert!(UI_LAYOUT_SRC.contains("preview_panel.set_hexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("build_panel_with_action(\"Upstream Media\""));
    assert!(
        !UI_LAYOUT_SRC.contains("gtk::SizeGroup::new(gtk::SizeGroupMode::Vertical)"),
        "the webcam testing column must not inherit the full height of the staging controls"
    );
}

#[test]
fn eye_placeholders_use_overlay_art_without_reflowing_the_shell() {
    assert!(UI_LAYOUT_SRC.contains("preview_overlay.add_overlay(&preview_placeholder);"));
    assert!(
        UI_LAYOUT_SRC.contains("preview_placeholder.set_visible(picture.paintable().is_none());")
    );
    assert!(UI_LAYOUT_SRC.contains("stack.add_named(&placeholder_box, Some(\"placeholder\"));"));
    assert!(UI_LAYOUT_SRC.contains("placeholder_overlay.add_overlay(&window_placeholder);"));
    assert!(
        !UI_LAYOUT_SRC.contains("placeholder_box.add_css_class(\"display-placeholder\");"),
        "open-eye placeholder should sit on the clear eye surface rather than an extra box"
    );
    assert!(UI_LAYOUT_SRC.contains("env!(\"CARGO_MANIFEST_DIR\")"));
    assert!(UI_LAYOUT_SRC.contains("/assets/placeholders/eye_{}_{}.png"));
    assert!(UI_LAYOUT_SRC.contains("picture.add_css_class(\"eye-preview-surface\");"));
    assert!(UI_LAYOUT_SRC.contains("preview_frame.add_css_class(\"eye-preview-surface\");"));
    assert!(UI_LAYOUT_SRC.contains("placeholder_frame.add_css_class(\"eye-preview-surface\");"));
    assert!(UI_LAYOUT_SRC.contains("overlay.eye-preview-surface"));
}

#[test]
fn device_testing_keeps_webcam_and_mic_playback_compact() {
    assert_eq!(const_i32("CAMERA_PREVIEW_VIEWPORT_WIDTH"), 480);
    assert_eq!(const_i32("CAMERA_PREVIEW_VIEWPORT_HEIGHT"), 270);
    assert!(UI_LAYOUT_SRC.contains("devices_panel.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("devices_body.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("media_group.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("testing_row.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("testing_row.set_valign(gtk::Align::Fill);"));
    assert!(UI_LAYOUT_SRC.contains("preview_panel.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("preview_body.set_hexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("webcam_group.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("webcam_group.set_valign(gtk::Align::Fill);"));
    assert!(UI_LAYOUT_SRC.contains("camera_preview.set_can_shrink(true);"));
    assert!(UI_LAYOUT_SRC.contains("camera_preview.set_vexpand(true);"));
    assert!(
        UI_LAYOUT_SRC.contains("camera_preview_idle.add_css_class(\"display-placeholder-art\");")
    );
    assert!(
        UI_LAYOUT_SRC.contains(
            "camera_preview_stack.add_named(&camera_preview_idle_shell, Some(\"idle\"));"
        )
    );
    assert!(
        UI_LAYOUT_SRC
            .contains("camera_preview_stack.add_named(&camera_preview_overlay, Some(\"live\"));")
    );
    assert!(UI_LAYOUT_SRC.contains("camera_preview_stack.set_visible_child_name(\"idle\");"));
    assert!(UI_LAYOUT_SRC.contains("camera_preview_frame.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("camera_preview_frame.set_valign(gtk::Align::Fill);"));
    assert!(UI_LAYOUT_SRC.contains("camera_preview_idle_frame.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("camera_preview_idle_frame.set_valign(gtk::Align::Fill);"));
    assert!(UI_LAYOUT_SRC.contains("playback_group.set_valign(gtk::Align::Fill);"));
    assert!(UI_LAYOUT_SRC.contains("playback_group.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("preview_body.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("playback_body.set_valign(gtk::Align::Fill);"));
    assert!(UI_LAYOUT_SRC.contains("audio_check_meter.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("playback_body.append(&audio_check_meter);"));
    assert!(UI_LAYOUT_SRC.contains("playback_body.append(&microphone_replay_button);"));
}

#[test]
fn operations_column_fills_height_and_splits_extra_space_between_logs() {
    assert_eq!(const_i32("SIDE_LOG_MIN_HEIGHT"), 124);
    assert_eq!(const_i32("SIDE_LOG_RECOVERY_BUDGET_SPLIT"), 102);
    assert!(UI_LAYOUT_SRC.contains("operations.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("operations.set_valign(gtk::Align::Fill);"));
    assert!(UI_LAYOUT_SRC.contains("diagnostics_panel.set_vexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("console_panel.set_vexpand(true);"));
    assert!(
        UI_LAYOUT_SRC.contains(
            "const SIDE_LOG_RECOVERY_MIN_HEIGHT: i32 = SIDE_LOG_MIN_HEIGHT - SIDE_LOG_RECOVERY_BUDGET_SPLIT;"
        ),
        "relay-control growth should reduce Diagnostics and Log minima through a shared split budget"
    );
    assert_eq!(
        UI_LAYOUT_SRC
            .matches(".min_content_height(SIDE_LOG_RECOVERY_MIN_HEIGHT)")
            .count(),
        2
    );
    assert_eq!(
        UI_LAYOUT_SRC
            .matches(".set_propagate_natural_height(false)")
            .count(),
        2,
        "Diagnostics and Log scrollports should split height by allocation rather than content"
    );
    assert_eq!(
        UI_LAYOUT_SRC
            .matches(".max_content_height(SIDE_LOG")
            .count(),
        0,
        "the docked logs must be allowed to split extra right-rail height"
    );
}

#[test]
fn session_console_buttons_share_the_remaining_toolbar_width() {
    assert!(
        UI_LAYOUT_SRC
            .contains("let console_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 8);")
    );
    assert!(UI_LAYOUT_SRC.contains("console_buttons.set_hexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("console_buttons.set_homogeneous(true);"));
    assert!(UI_LAYOUT_SRC.contains("console_copy_button.set_hexpand(true);"));
    assert!(UI_LAYOUT_SRC.contains("console_popout_button.set_hexpand(true);"));
    assert!(
        source_index("console_toolbar.append(&console_level_combo);")
            < source_index("console_toolbar.append(&console_buttons);")
    );
}

#[test]
fn status_chip_text_is_centered_inside_each_pill() {
    assert!(UI_LAYOUT_SRC.contains("meta.set_halign(gtk::Align::Center);"));
    assert!(
        UI_LAYOUT_SRC
            .matches("set_halign(gtk::Align::Center);")
            .count()
            >= 7,
        "chip labels and values should be horizontally centered"
    );
    assert!(
        UI_LAYOUT_SRC.matches("set_xalign(0.5);").count() >= 6,
        "chip text lines should center their own text, not only their widgets"
    );
    assert!(UI_LAYOUT_SRC.contains("build_status_chip_with_light(\"Left\", \"Off\")"));
    assert!(UI_LAYOUT_SRC.contains("build_status_chip_with_light(\"Right\", \"Off\")"));
    assert!(UI_LAYOUT_SRC.contains("build_status_chip_with_light(\"Lag\", \"???\")"));
    assert!(UI_LAYOUT_SRC.contains("chips.append(&upstream_lag_chip);"));
    assert!(UI_LAYOUT_SRC.contains("upstream_lag_value"));
}

#[test]
fn relay_controls_keep_connect_inline_with_server_entry() {
    assert!(UI_LAYOUT_SRC.contains("build_panel(\"Relay\")"));
    assert_eq!(const_i32("OPERATIONS_RAIL_WIDTH"), 276);
    assert_eq!(const_i32("RELAY_SUBGROUP_LABEL_WIDTH"), 8);
    assert_eq!(const_i32("RAIL_BUTTON_WIDTH"), 83);
    assert_eq!(const_i32("RAIL_BUTTON_LABEL_CHARS"), 10);
    assert!(UI_LAYOUT_SRC.contains("let relay_grid = gtk::Grid::new();"));
    assert!(UI_LAYOUT_SRC.contains("server_entry.set_width_chars(11);"));
    assert!(UI_LAYOUT_SRC.contains("relay_grid.set_column_homogeneous(false);"));
    assert!(UI_LAYOUT_SRC.contains("relay_grid.attach(&server_entry, 0, 0, 1, 1);"));
    assert!(UI_LAYOUT_SRC.contains("let certs_button = rail_button(\"Certs\""));
    assert!(UI_LAYOUT_SRC.contains("let start_button = rail_button(\"Connect\""));
    assert!(UI_LAYOUT_SRC.contains("pub(crate) fn set_rail_button_label("));
    assert!(UI_LAYOUT_SRC.contains("relay_grid.attach(&certs_button, 1, 0, 1, 1);"));
    assert!(UI_LAYOUT_SRC.contains("relay_grid.attach(&start_button, 2, 0, 1, 1);"));
    assert!(UI_LAYOUT_SRC.contains("stabilize_button(&certs_button, 66);"));
    assert!(UI_LAYOUT_SRC.contains("start_button.set_hexpand(false);"));
    assert!(!UI_LAYOUT_SRC.contains("stabilize_button(&start_button, 76);"));
    assert!(
        UI_LAYOUT_SRC
            .contains("let recovery_heading = gtk::Label::new(Some(\"Recover\\nUpstream\"));")
    );
    assert!(
        UI_LAYOUT_SRC
            .contains("let recovery_row = gtk::Box::new(gtk::Orientation::Horizontal, 8);")
    );
    assert!(
        UI_LAYOUT_SRC
            .contains("let recovery_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 8);")
    );
    assert!(UI_LAYOUT_SRC.contains("recovery_buttons.set_homogeneous(false);"));
    assert!(
        UI_LAYOUT_SRC.contains("recovery_heading.set_width_chars(RELAY_SUBGROUP_LABEL_WIDTH);")
    );
    assert!(UI_LAYOUT_SRC.contains(
        "let calibration_heading = gtk::Label::new(Some(\"Audio/Video\\nUpstream\\nCalibration\"));"
    ));
    assert!(UI_LAYOUT_SRC.contains("calibration_heading.set_justify(gtk::Justification::Center);"));
    assert!(
        UI_LAYOUT_SRC.contains("calibration_heading.set_width_chars(RELAY_SUBGROUP_LABEL_WIDTH);")
    );
    assert!(UI_LAYOUT_SRC.contains("let calibration_buttons = gtk::Grid::new();"));
    assert!(UI_LAYOUT_SRC.contains("calibration_buttons.set_column_homogeneous(true);"));
    assert!(UI_LAYOUT_SRC.contains("let calibration_default_button = rail_button("));
    assert!(UI_LAYOUT_SRC.contains("let calibration_factory_button = rail_button("));
    assert!(UI_LAYOUT_SRC.contains("let calibration_blind_button = rail_button("));
    assert!(UI_LAYOUT_SRC.contains("let calibration_minus_button = rail_button("));
    assert!(UI_LAYOUT_SRC.contains("let calibration_plus_button = rail_button("));
    assert!(UI_LAYOUT_SRC.contains("let calibration_rig_button = rail_button("));
    assert!(UI_LAYOUT_SRC.contains("let tools_heading = gtk::Label::new(Some(\"Tools\"));"));
    assert!(
        UI_LAYOUT_SRC.contains("let tools_row = gtk::Box::new(gtk::Orientation::Horizontal, 8);")
    );
    assert!(
        UI_LAYOUT_SRC
            .contains("let tools_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 8);")
    );
    assert!(UI_LAYOUT_SRC.contains("tools_buttons.set_homogeneous(false);"));
    assert!(UI_LAYOUT_SRC.contains("tools_heading.set_width_chars(RELAY_SUBGROUP_LABEL_WIDTH);"));
    assert!(UI_LAYOUT_SRC.contains("let clipboard_button = rail_button(\"Clipboard\""));
    assert!(UI_LAYOUT_SRC.contains("let wake_combo = gtk::ComboBoxText::new();"));
    assert!(UI_LAYOUT_SRC.contains("(\"off\", \"Wake: off\")"));
    assert!(UI_LAYOUT_SRC.contains("(\"60\", \"Wake: 60m\")"));
    assert!(UI_LAYOUT_SRC.contains("wake_combo.set_size_request(92, 36);"));
    assert!(UI_LAYOUT_SRC.contains("tools_buttons.append(&wake_combo);"));
    assert!(UI_LAYOUT_SRC.contains("let usb_recover_button = rail_button("));
    assert!(UI_LAYOUT_SRC.contains("usb_recover_button.set_hexpand(false);"));
    assert!(UI_LAYOUT_SRC.contains("\"HID\","));
    assert!(UI_LAYOUT_SRC.contains("let uac_recover_button = rail_button("));
    assert!(UI_LAYOUT_SRC.contains("uac_recover_button.set_hexpand(false);"));
    assert!(UI_LAYOUT_SRC.contains("\"Audio\","));
    assert!(UI_LAYOUT_SRC.contains("let uvc_recover_button = rail_button("));
    assert!(UI_LAYOUT_SRC.contains("uvc_recover_button.set_hexpand(false);"));
    assert!(UI_LAYOUT_SRC.contains("\"Video\","));
    assert!(UI_LAYOUT_SRC.contains("recovery_buttons.append(&usb_recover_button);"));
    assert!(UI_LAYOUT_SRC.contains("recovery_buttons.append(&uac_recover_button);"));
    assert!(UI_LAYOUT_SRC.contains("recovery_buttons.append(&uvc_recover_button);"));
    assert!(
        source_index("let recovery_heading = gtk::Label::new(Some(\"Recover\\nUpstream\"));")
            < source_index(
                "let calibration_heading = gtk::Label::new(Some(\"Audio/Video\\nUpstream\\nCalibration\"));"
            )
    );
    assert!(
        source_index(
            "let calibration_heading = gtk::Label::new(Some(\"Audio/Video\\nUpstream\\nCalibration\"));"
        ) < source_index("let power_heading = gtk::Label::new(Some(\"GPIO Power\"));")
    );
    assert!(UI_LAYOUT_SRC.contains("tools_buttons.append(&clipboard_button);"));
    assert!(!UI_LAYOUT_SRC.contains("Gate Probe"));
    assert!(UI_LAYOUT_SRC.contains("text.set_ellipsize(pango::EllipsizeMode::End);"));
    assert!(
        source_index("relay_grid.attach(&server_entry, 0, 0, 1, 1);")
            < source_index("relay_grid.attach(&certs_button, 1, 0, 1, 1);")
    );
    assert!(
        source_index("relay_grid.attach(&certs_button, 1, 0, 1, 1);")
            < source_index("relay_grid.attach(&start_button, 2, 0, 1, 1);")
    );
}

#[test]
fn media_controls_own_stream_toggles_and_inline_gain_controls() {
    assert!(!UI_LAYOUT_SRC.contains("Remote Audio"));
    assert!(
        UI_LAYOUT_SRC.contains("let power_shell = gtk::Box::new(gtk::Orientation::Vertical, 6);")
    );
    assert!(!UI_LAYOUT_SRC.contains("let channel_heading = gtk::Label::new(Some(\"Streams\"));"));
    assert!(UI_LAYOUT_SRC.contains("gtk::ToggleButton::with_label(\"Camera\")"));
    assert!(UI_LAYOUT_SRC.contains("gtk::ToggleButton::with_label(\"Mic\")"));
    assert!(UI_LAYOUT_SRC.contains("gtk::ToggleButton::with_label(\"🧹\")"));
    assert!(
        UI_LAYOUT_SRC.contains("Noise cancellation is on for the upstream microphone.")
            && UI_LAYOUT_SRC
                .contains("Noise cancellation is off; upstream microphone is raw aside from gain.")
    );
    assert!(UI_LAYOUT_SRC.contains("gtk::ToggleButton::with_label(\"Speaker\")"));
    assert!(UI_LAYOUT_SRC.contains("camera_channel_toggle.add_css_class(\"media-toggle\");"));
    assert!(UI_LAYOUT_SRC.contains("audio_channel_toggle.add_css_class(\"media-toggle\");"));
    assert!(UI_LAYOUT_SRC.contains("microphone_channel_toggle.add_css_class(\"media-toggle\");"));
    assert!(
        UI_LAYOUT_SRC.contains("microphone_channel_toggle.add_css_class(\"media-toggle-split\");")
    );
    assert!(UI_LAYOUT_SRC.contains("stabilize_button(&microphone_channel_toggle, 44);"));
    assert!(
        UI_LAYOUT_SRC.contains("noise_suppression_toggle.add_css_class(\"media-toggle-split\");")
    );
    assert!(UI_LAYOUT_SRC.contains("stabilize_button(&noise_suppression_toggle, 44);"));
    assert!(UI_LAYOUT_SRC.contains("microphone_toggle_group.set_homogeneous(true);"));
    assert!(UI_LAYOUT_SRC.contains("microphone_toggle_group.set_size_request(92, -1);"));
    assert!(UI_LAYOUT_SRC.contains("button.media-toggle:checked"));
    assert!(UI_LAYOUT_SRC.contains("button.media-toggle-split"));
    assert!(UI_LAYOUT_SRC.contains("let camera_quality_combo = gtk::ComboBoxText::new();"));
    assert!(UI_LAYOUT_SRC.contains("sync_camera_quality_combo("));
    assert!(UI_LAYOUT_SRC.contains("camera_quality_combo.set_size_request(88, -1);"));
    assert!(
        UI_LAYOUT_SRC
            .contains("let camera_selectors = gtk::Box::new(gtk::Orientation::Horizontal, 6);")
    );
    assert!(UI_LAYOUT_SRC.contains("camera_selectors.append(&camera_combo);"));
    assert!(UI_LAYOUT_SRC.contains("camera_selectors.append(&camera_quality_combo);"));
    assert!(
        source_index("camera_selectors.append(&camera_combo);")
            < source_index("camera_selectors.append(&camera_quality_combo);")
    );
    assert!(
        UI_LAYOUT_SRC
            .contains("let speaker_selectors = gtk::Box::new(gtk::Orientation::Horizontal, 6);")
    );
    assert!(UI_LAYOUT_SRC.contains("speaker_selectors.append(&speaker_combo);"));
    assert!(UI_LAYOUT_SRC.contains("speaker_selectors.append(&audio_gain_scale);"));
    assert!(UI_LAYOUT_SRC.contains("label_widget.set_width_chars(7);"));
    assert!(
        UI_LAYOUT_SRC
            .contains("let microphone_selectors = gtk::Box::new(gtk::Orientation::Horizontal, 6);")
    );
    assert!(UI_LAYOUT_SRC.contains("microphone_selectors.append(&microphone_combo);"));
    assert!(UI_LAYOUT_SRC.contains("microphone_selectors.append(&mic_gain_scale);"));
    assert!(
        UI_LAYOUT_SRC.contains("let upstream_audio_transport_combo = gtk::ComboBoxText::new();")
    );
    assert!(UI_LAYOUT_SRC.contains(
        "upstream_audio_transport_combo.append(Some(transport.as_id()), transport.label());"
    ));
    assert!(
        UI_LAYOUT_SRC
            .contains("PCM is the known-good default; Opus is compressed and experimental.")
    );
    assert!(UI_LAYOUT_SRC.contains("upstream_transport_row.append(&webcam_transport_combo);"));
    assert!(
        UI_LAYOUT_SRC.contains("upstream_transport_row.append(&upstream_audio_transport_combo);")
    );
    assert!(UI_LAYOUT_SRC.contains("let playback_group = build_subgroup(\"Mic Playback\");"));
    assert_eq!(
        UI_LAYOUT_SRC
            .matches("attach_device_control_row(\n        &media_grid")
            .count(),
        3
    );
    assert!(!UI_LAYOUT_SRC.contains("camera_combo.append(Some(\"auto\")"));
    assert!(!UI_LAYOUT_SRC.contains("speaker_combo.append(Some(\"auto\")"));
    assert!(!UI_LAYOUT_SRC.contains("microphone_combo.append(Some(\"auto\")"));
    assert!(UI_LAYOUT_SRC.contains("let power_heading = gtk::Label::new(Some(\"GPIO Power\"));"));
    assert!(UI_LAYOUT_SRC.contains("power_row.append(&power_heading);"));
    assert!(UI_LAYOUT_SRC.contains("power_buttons.set_homogeneous(true);"));
    assert!(UI_LAYOUT_SRC.contains("let audio_gain_scale ="));
    assert!(UI_LAYOUT_SRC.contains("audio_gain_scale.set_draw_value(false);"));
    assert!(UI_LAYOUT_SRC.contains("audio_gain_scale.set_size_request(96, -1);"));
    assert!(UI_LAYOUT_SRC.contains("let mic_gain_scale ="));
    assert!(UI_LAYOUT_SRC.contains("mic_gain_scale.set_draw_value(false);"));
    assert!(UI_LAYOUT_SRC.contains("mic_gain_scale.set_size_request(96, -1);"));
    assert!(!UI_LAYOUT_SRC.contains("audio_gain_row.set_size_request(220, -1);"));
    assert!(!UI_LAYOUT_SRC.contains("mic_gain_row.set_size_request(220, -1);"));
    assert!(!UI_LAYOUT_SRC.contains("power_shell.append(&audio_gain_row);"));
    assert!(!UI_LAYOUT_SRC.contains("power_shell.append(&mic_gain_row);"));
    assert_eq!(
        UI_LAYOUT_SRC
            .matches("connection_body.append(&gtk::Separator::new(gtk::Orientation::Horizontal));")
            .count(),
        4,
        "recover/calibration/gpio/inputs/tools sections should remain visually separated"
    );
    assert!(
        source_index("let power_heading = gtk::Label::new(Some(\"GPIO Power\"));")
            < source_index("let routing_heading = gtk::Label::new(Some(\"Inputs\"));")
    );
    assert!(
        source_index("power_shell.append(&power_row);")
            < source_index("let routing_heading = gtk::Label::new(Some(\"Inputs\"));")
    );
    assert!(
        source_index("let routing_heading = gtk::Label::new(Some(\"Inputs\"));")
            < source_index("let tools_heading = gtk::Label::new(Some(\"Tools\"));")
    );
    assert!(UI_LAYOUT_SRC.contains("routing_buttons.set_homogeneous(true);"));
}
