use anyhow::Result;

#[cfg(not(coverage))]
use {
    super::calibration::{
        blind_calibration_estimate, fetch_calibration, fetch_upstream_sync,
        nudge_audio_calibration, restore_default_calibration, restore_factory_calibration,
    },
    super::clipboard::send_clipboard_text_to_remote,
    super::device_test::{DeviceTestController, DeviceTestKind},
    super::devices::{CameraMode, DeviceCatalog},
    super::diagnostics::PerformanceSample,
    super::launcher_clipboard_control_path,
    super::launcher_focus_signal_path,
    super::power::{
        fetch_capture_power, recover_uac_soft, recover_usb_soft, recover_uvc_soft,
        set_capture_power_mode,
    },
    super::preview::{LauncherPreview, PreviewFrameSnapshot, PreviewRecordingTap, PreviewSurface},
    super::state::{
        BreakoutSizePreset, CalibrationStatus, CapturePowerStatus, CaptureSizePreset,
        DisplaySurface, FeedSourcePreset, InputRouting, LauncherState, MAX_AUDIO_GAIN_PERCENT,
        MAX_MIC_GAIN_PERCENT, UpstreamAudioTransport, UpstreamSyncStatus, WebcamTransport,
    },
    super::ui_components::{
        ConsoleLogLevel, build_launcher_view, sync_camera_quality_combo, sync_input_device_combo,
        sync_stage_device_combo,
    },
    super::ui_runtime::{
        RelayChild, append_session_log_for_level, apply_popout_window_size,
        attach_child_log_streams, audio_gain_control_path, capture_swap_key, copy_plain_text,
        copy_session_log, dock_all_displays_to_preview, dock_display_to_preview,
        input_control_path, input_state_path, input_toggle_control_path, media_control_path,
        mic_gain_control_path, next_input_routing, open_diagnostics_popout, open_popout_window,
        open_session_log_popout, path_marker, present_popout_windows, read_input_routing_state,
        reap_exited_child, refresh_launcher_ui, refresh_test_buttons, routing_name,
        selected_combo_value, selected_server_addr, shutdown_launcher_runtime,
        spawn_client_process, stop_child_process, toggle_key_label, update_test_action_result,
        uplink_camera_preview_path, uplink_mic_level_path, uplink_telemetry_path,
        wake_control_path, write_audio_gain_request, write_input_routing_request,
        write_input_toggle_key_request, write_media_control_request, write_mic_gain_request,
        write_wake_control_request,
    },
    crate::handshake::{HandshakeProbe, probe},
    crate::output::display::enumerate_monitors,
    gtk::glib,
    gtk::prelude::*,
    lesavka_common::lesavka::CapturePowerCommand,
    lesavka_common::process_metrics::ProcessCpuSampler,
    serde_json::json,
    std::cell::{Cell, RefCell},
    std::collections::VecDeque,
    std::path::{Path, PathBuf},
    std::process::Command,
    std::rc::Rc,
    std::time::{Duration, Instant, SystemTime, UNIX_EPOCH},
};

include!("ui/message_and_network_state.rs");
#[cfg(not(coverage))]
include!("ui/control_requests.rs");
#[cfg(not(coverage))]
include!("ui/diagnostic_sampling.rs");
#[cfg(not(coverage))]
include!("ui/preview_profiles.rs");
#[cfg(not(coverage))]
include!("ui/activation_context.rs");
#[cfg(not(coverage))]
include!("ui/startup_window_guard.rs");
#[cfg(not(coverage))]
include!("ui/eye_capture_bindings/recording_support.rs");
#[cfg(not(coverage))]
include!("ui/eye_capture_bindings/recording_worker.rs");
#[cfg(not(coverage))]
include!("ui/utility_button_bindings/pki_support.rs");
#[cfg(coverage)]
include!("ui/session_preview_coverage.rs");

#[cfg(not(coverage))]
pub fn run_gui_launcher(server_addr: String) -> Result<()> {
    let app = gtk::Application::builder()
        .application_id("dev.lesavka.launcher")
        .build();
    let catalog = Rc::new(RefCell::new(DeviceCatalog::discover()));
    let state = Rc::new(RefCell::new(LauncherState::new()));
    state.borrow_mut().apply_catalog_defaults(&catalog.borrow());
    let child_proc = Rc::new(RefCell::new(None::<RelayChild>));
    let tests = Rc::new(RefCell::new(DeviceTestController::new()));
    let server_addr = Rc::new(server_addr);
    let focus_signal_path = Rc::new(launcher_focus_signal_path());
    let clipboard_control_path = Rc::new(launcher_clipboard_control_path());
    let input_control_path = Rc::new(input_control_path());
    let input_state_path = Rc::new(input_state_path());
    let input_toggle_control_path = Rc::new(input_toggle_control_path());
    let wake_control_file = Rc::new(wake_control_path());
    let _ = std::fs::remove_file(focus_signal_path.as_path());
    let _ = std::fs::remove_file(clipboard_control_path.as_path());
    let _ = std::fs::remove_file(input_control_path.as_path());
    let _ = std::fs::remove_file(input_state_path.as_path());
    let _ = std::fs::remove_file(input_toggle_control_path.as_path());
    let _ = std::fs::remove_file(wake_control_file.as_path());

    {
        let child_proc = Rc::clone(&child_proc);
        let focus_signal_path = Rc::clone(&focus_signal_path);
        let clipboard_control_path = Rc::clone(&clipboard_control_path);
        let input_control_path = Rc::clone(&input_control_path);
        let input_state_path = Rc::clone(&input_state_path);
        let input_toggle_control_path = Rc::clone(&input_toggle_control_path);
        let wake_control_file = Rc::clone(&wake_control_file);
        let tests = Rc::clone(&tests);
        app.connect_shutdown(move |_| {
            stop_child_process(&child_proc);
            tests.borrow_mut().stop_all();
            let _ = std::fs::remove_file(focus_signal_path.as_path());
            let _ = std::fs::remove_file(clipboard_control_path.as_path());
            let _ = std::fs::remove_file(input_control_path.as_path());
            let _ = std::fs::remove_file(input_state_path.as_path());
            let _ = std::fs::remove_file(input_toggle_control_path.as_path());
            let _ = std::fs::remove_file(wake_control_file.as_path());
        });
    }

    {
        let catalog = Rc::clone(&catalog);
        let state = Rc::clone(&state);
        let child_proc = Rc::clone(&child_proc);
        let tests = Rc::clone(&tests);
        let server_addr = Rc::clone(&server_addr);
        let focus_signal_path = Rc::clone(&focus_signal_path);
        let input_control_path = Rc::clone(&input_control_path);
        let input_state_path = Rc::clone(&input_state_path);
        let input_toggle_control_path = Rc::clone(&input_toggle_control_path);

        app.connect_activate(move |app| {
            let ActivationContext {
                window,
                launcher_size,
                server_entry,
                camera_combo,
                camera_quality_combo,
                microphone_combo,
                speaker_combo,
                keyboard_combo,
                mouse_combo,
                widgets,
                preview,
                popouts,
                diagnostics_popout,
                log_popout,
                camera_quality_syncing,
                power_tx,
                power_rx,
                power_request_in_flight,
                calibration_tx,
                calibration_rx,
                calibration_request_in_flight,
                upstream_sync_tx,
                upstream_sync_rx,
                upstream_sync_request_in_flight,
                relay_tx,
                relay_rx,
                relay_request_in_flight,
                caps_tx,
                caps_rx,
                caps_request_in_flight,
                diagnostics_network,
                diagnostics_process,
                disconnect_cooldown_until,
                next_power_probe,
                next_calibration_probe,
                next_upstream_sync_probe,
                next_diagnostics_probe,
                next_diagnostics_sample,
                preview_session_active,
                clipboard_tx,
                clipboard_rx,
                log_tx,
                log_rx,
            } = include!("ui/activation_setup.rs");

            include!("ui/stage_device_bindings.rs");
            include!("ui/eye_display_bindings.rs");
            include!("ui/media_device_bindings.rs");
            let _: () = include!("ui/device_refresh_binding.rs");
            include!("ui/relay_input_bindings.rs");
            include!("ui/eye_capture_bindings.rs");
            include!("ui/utility_button_bindings.rs");
            include!("ui/local_test_bindings.rs");
            include!("ui/power_display_key_bindings.rs");
            let _: () = include!("ui/runtime_poll.rs");

            window.present();
            schedule_launcher_window_guard(app, &window, launcher_size);
        });
    }

    let _ = app.run_with_args::<&str>(&[]);
    Ok(())
}

#[cfg(coverage)]
pub fn run_gui_launcher(_server_addr: String) -> Result<()> {
    Ok(())
}

#[cfg(all(test, not(coverage)))]
#[path = "tests/ui_preview_profiles.rs"]
mod tests;

#[cfg(all(test, coverage))]
#[path = "tests/ui_coverage.rs"]
mod tests;
