// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

pub mod tauri_handlers;
pub mod uninstall;
pub mod utils;

use std::path::Path;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};

use tauri::State;
use tauri::menu::{CheckMenuItemBuilder, Menu, MenuItemBuilder};
use tauri::tray::TrayIconBuilder;
use tauri::{AppHandle, Manager, RESTART_EXIT_CODE, Runtime};
use tauri_plugin_dialog::DialogExt;

#[cfg(target_os = "windows")]
extern crate winapi;

use crate::tauri_handlers::startup::{
    abort_installation, create_default_backend_services, get_installation_status, install_conda,
    install_to_directory, setup_python_environment,
};

use crate::tauri_handlers::environments::{
    create_environment, create_environment_from_requirements, execute_in_environment,
    get_environment_extensions, install_extensions, list_conda_environments, remove_environment,
    remove_extension, select_requirements_file, update_environment, update_extension,
    update_installation_error,
};

use crate::tauri_handlers::jupyter::{
    check_jupyter_server, list_jupyter_servers, open_jupyter_logs_window, start_jupyter_server,
    stop_all_jupyter_servers, stop_jupyter_server, update_jupyter_status,
};

use crate::tauri_handlers::credentials::{
    get_user_credentials, open_credentials_file, update_user_credentials,
};

use crate::tauri_handlers::backends::{
    create_backend_service, delete_backend_service, initialize_backends, list_backend_services,
    open_backend_logs_window, start_backend_service, stop_backend_service, update_backend_service,
};

use crate::utils::certs::generate_self_signed_cert;

use crate::tauri_handlers::helpers::{
    check_directory_exists, check_file_exists, get_home_directory, get_installation_directory,
    get_or_create_app_id, get_settings_directory, get_userdata_directory, get_working_directory,
    open_url_in_window, open_workspace_in_browser, save_working_directory, select_directory,
    select_file, toggle_theme, update_openbb_settings,
};

use tauri_plugin_updater::UpdaterExt;

use crate::utils::process_monitor::{
    GetProcessLogsRequest, LogEntry, LogStorage, RunningProcesses, clear_process_logs,
    get_log_storage, get_process_logs, init_process_monitoring, register_process,
    unregister_process,
};

use crate::uninstall::uninstall_application;

#[derive(Clone, serde::Serialize)]
struct InstallationState {
    is_installed: bool,
    installation_directory: Option<String>,
}

#[derive(Clone)]
struct ProcessLogState(LogStorage);

#[tauri::command]
fn register_process_monitoring(state: State<ProcessLogState>, process_id: String) -> bool {
    register_process(&state.0, &process_id)
}

#[tauri::command]
fn unregister_process_monitoring(state: State<ProcessLogState>, process_id: String) -> bool {
    unregister_process(&state.0, &process_id)
}

#[tauri::command]
fn get_process_logs_history(
    state: State<ProcessLogState>,
    process_id: String,
    count: Option<usize>,
) -> Vec<LogEntry> {
    let request = GetProcessLogsRequest { process_id, count };
    get_process_logs(&state.0.clone(), request)
}

#[tauri::command]
fn clear_process_logs_history(state: State<ProcessLogState>, process_id: String) -> bool {
    clear_process_logs(&state.0, &process_id)
}

async fn check_and_apply_update(app: AppHandle, always_prompt: bool) {
    let show_error = |app: &AppHandle, title: &str, message: String| {
        app.dialog()
            .message(message)
            .title(title)
            .kind(tauri_plugin_dialog::MessageDialogKind::Error)
            .show(|_| {});
    };
    let update_url = "https://github.com/OpenBB-finance/OpenBB/releases/download/ODP/latest.json";

    let ap_id = get_or_create_app_id();

    let headers = {
        let mut headers = reqwest::header::HeaderMap::new();

        match reqwest::header::HeaderValue::from_str("ODP-Updater") {
            Ok(user_agent) => {
                headers.insert(reqwest::header::USER_AGENT, user_agent);
            }
            Err(e) => {
                log::error!("Failed to create User-Agent header: {}", e);
                if always_prompt {
                    show_error(
                        &app,
                        "Update Check Failed",
                        format!("Failed to create User-Agent header: {}", e),
                    );
                }
                return;
            }
        }

        match reqwest::header::HeaderValue::from_str(&ap_id) {
            Ok(app_id) => {
                headers.insert(reqwest::header::HeaderName::from_static("x-app-id"), app_id);
            }
            Err(e) => {
                log::error!("Failed to create X-App-ID header: {}", e);
                if always_prompt {
                    show_error(
                        &app,
                        "Update Check Failed",
                        format!("Failed to create X-App-ID header: {}", e),
                    );
                }
                return;
            }
        }

        headers
    };

    let url = match update_url.parse() {
        Ok(url) => url,
        Err(e) => {
            let err_msg = format!("Failed to parse update URL: {}", e);
            log::error!("{}", err_msg);
            if always_prompt {
                show_error(&app, "Update Check Failed", err_msg);
            }
            return;
        }
    };

    let updater_res = app
        .updater_builder()
        .headers(headers)
        .endpoints(vec![url])
        .and_then(|builder| builder.build());

    match updater_res {
        Ok(updater) => {
            match updater.check().await {
                Ok(Some(update)) => {
                    let app_clone = app.clone();
                    app.dialog()
                    .message(format!(
                        "A new version ({}) is available. Would you like to install it now? The update will close the application and restart.",
                        update.version
                    ))
                    .title("Update Available")
                    .kind(tauri_plugin_dialog::MessageDialogKind::Info)
                    .buttons(tauri_plugin_dialog::MessageDialogButtons::YesNo)
                    .show(move |install| {
                        if install {
                            let app_clone_inner = app_clone.clone();
                            tauri::async_runtime::spawn(async move {
                                if let Some(window) = app_clone_inner.get_webview_window("main") {
                                    let _ = window.show();
                                    let _ = window.set_focus();
                                }

                                if let Err(e) = update.download_and_install(|_, _| {}, || {}).await
                                {
                                    log::error!("Failed to install update: {}", e);
                                    show_error(
                                        &app_clone_inner,
                                        "Update Failed",
                                        format!("Failed to install update: {}", e),
                                    );
                                } else {
                                    log::info!("Update installed successfully, restarting...");

                                    // SET THE FLAG TO SHOW WINDOW AFTER RESTART
                                    if let Ok(home_dir) = std::env::var("HOME").or_else(|_| std::env::var("USERPROFILE")) {
                                        let flag_path = std::path::Path::new(&home_dir).join(".openbb_platform").join(".show_on_restart");
                                        let _ = std::fs::write(flag_path, "1");
                                        log::info!("Set flag to show window on restart");
                                    }

                                    if let Some(window) = app_clone_inner.get_webview_window("main") {
                                        let _ = window.show();
                                    }

                                    app_clone_inner.request_restart();

                                    /* #[cfg(not(target_os = "macos"))]
                                    {
                                        use std::process::Command;

                                        if let Ok(exe_path) = std::env::current_exe() {
                                            log::debug!("Relaunching from: {}", exe_path.display());
                                            let _ = Command::new(exe_path).spawn();
                                            std::process::exit(0);
                                        } else {
                                            log::error!("Could not determine executable path for restart");
                                            app_clone_inner.restart();
                                        }
                                    }
                                    */
                                }
                            });
                        }
                    });
                }
                Ok(None) => {
                    log::debug!("No updates available");
                    if always_prompt {
                        app.dialog()
                            .message("You are already running the latest version.")
                            .title("No Updates Available")
                            .kind(tauri_plugin_dialog::MessageDialogKind::Info)
                            .show(|_| {});
                    }
                }
                Err(e) => {
                    let err_msg = format!("Failed to check for updates: {}", e);
                    log::error!("{}", err_msg);
                    if always_prompt {
                        show_error(&app, "Update Check Failed", err_msg);
                    }
                }
            }
        }
        Err(e) => {
            let err_msg = format!("Failed to build updater: {}", e);
            log::error!("{}", err_msg);
            if always_prompt {
                show_error(&app, "Update Check Failed", err_msg);
            }
        }
    }
}

async fn trigger_update_dialog(app: AppHandle) {
    check_and_apply_update(app, true).await;
}

async fn background_update_check(app: AppHandle) {
    check_and_apply_update(app, false).await;
}

fn check_installation_on_startup() -> InstallationState {
    log::debug!("STARTUP: Checking installation status");

    let home_dir = match std::env::var("HOME").or_else(|_| std::env::var("USERPROFILE")) {
        Ok(dir) => dir,
        Err(e) => {
            log::debug!("STARTUP: Failed to get home directory: {e}");
            return InstallationState {
                is_installed: false,
                installation_directory: None,
            };
        }
    };

    let platform_dir = Path::new(&home_dir).join(".openbb_platform");
    let system_settings_path = platform_dir.join("system_settings.json");

    log::debug!(
        "STARTUP: Looking for system settings at: {}",
        system_settings_path.display()
    );

    if !system_settings_path.exists() {
        log::debug!("STARTUP: System settings file not found");
        return InstallationState {
            is_installed: false,
            installation_directory: None,
        };
    }

    log::debug!("STARTUP: System settings file found");

    let settings_content = match std::fs::read_to_string(&system_settings_path) {
        Ok(content) => content,
        Err(e) => {
            log::debug!("STARTUP: Failed to read settings file: {e}");
            return InstallationState {
                is_installed: false,
                installation_directory: None,
            };
        }
    };

    let settings: serde_json::Value = match serde_json::from_str(&settings_content) {
        Ok(json) => json,
        Err(e) => {
            log::debug!("STARTUP: Failed to parse settings JSON: {e}");
            return InstallationState {
                is_installed: false,
                installation_directory: None,
            };
        }
    };

    let mut install_dir = None;

    if let Some(install_settings) = settings.get("install_settings")
        && let Some(dir) = install_settings.get("installation_directory")
        && let Some(dir_str) = dir.as_str()
    {
        log::debug!("STARTUP: Found installation directory in install_settings: {dir_str}");
        let conda_dir = Path::new(dir_str).join("conda");

        let conda_exe = if cfg!(target_os = "windows") {
            conda_dir.join("Scripts").join("conda.exe")
        } else {
            conda_dir.join("bin").join("conda")
        };

        if conda_exe.exists() {
            log::debug!("STARTUP: Conda executable found at {}", conda_exe.display());
            install_dir = Some(dir_str.to_string());
        } else {
            log::debug!(
                "STARTUP: Conda executable not found at {}",
                conda_exe.display()
            );
        }
    }

    if install_dir.is_none()
        && let Some(dir) = settings.get("installation_directory")
        && let Some(dir_str) = dir.as_str()
    {
        log::debug!("STARTUP: Found installation directory at root level: {dir_str}");
        let conda_dir = Path::new(dir_str).join("conda");

        let conda_exe = if cfg!(target_os = "windows") {
            conda_dir.join("Scripts").join("conda.exe")
        } else {
            conda_dir.join("bin").join("conda")
        };

        if conda_exe.exists() {
            log::debug!("STARTUP: Conda executable found at {}", conda_exe.display());
            install_dir = Some(dir_str.to_string());
        } else {
            log::debug!(
                "STARTUP: Conda executable not found at {}",
                conda_exe.display()
            );
        }
    }

    let is_installed = install_dir.is_some();
    log::debug!(
        "STARTUP: Installation status: {}",
        if is_installed { "VALID" } else { "INVALID" }
    );

    InstallationState {
        is_installed,
        installation_directory: install_dir,
    }
}

#[tauri::command]
fn get_installation_state(state: tauri::State<InstallationState>) -> InstallationState {
    state.inner().clone()
}

#[tauri::command]
fn navigate_to_page<R: Runtime>(app_handle: AppHandle<R>, page: &str) {
    if let Some(window) = app_handle.get_webview_window("main") {
        let _ = window.show();
        let _ = window.set_focus();

        let js = format!(
            r#"
            if (localStorage.getItem('environments-first-load-done') === 'true') {{
                window.location.href = '{page}';
            }} else {{
                console.log('Navigation prevented: environments-first-load-done not set');
            }}
            "#
        );
        let _ = window.eval(&js);
    }
}

#[tauri::command]
async fn quit_application(app_handle: AppHandle) {
    log::debug!("Quit application command received, running cleanup...");
    cleanup_all_processes(app_handle.clone()).await;
    app_handle.exit(0);
}

async fn cleanup_all_processes(app_handle: AppHandle) {
    use crate::tauri_handlers::helpers::{RealEnvSystem, RealFileExtTrait, RealFileSystem};
    log::debug!("Running complete application cleanup");

    let cleanup_timeout = std::time::Duration::from_secs(10);

    let cleanup_result = tokio::time::timeout(cleanup_timeout, async {
        match tokio::time::timeout(
            std::time::Duration::from_secs(3),
            tauri_handlers::jupyter::stop_all_jupyter_servers(app_handle.clone()),
        )
        .await
        {
            Ok(Ok(_)) => log::debug!("Successfully stopped all Jupyter servers"),
            Ok(Err(e)) => log::error!("Error stopping Jupyter servers: {e}"),
            Err(_) => log::warn!("Jupyter servers shutdown timed out"),
        }

        match tokio::time::timeout(
            std::time::Duration::from_secs(3),
            tauri_handlers::backends::stop_all_backend_services(
                app_handle,
                &RealFileSystem,
                &RealEnvSystem,
                &RealFileExtTrait,
            ),
        )
        .await
        {
            Ok(Ok(_)) => log::debug!("Successfully stopped all backend services"),
            Ok(Err(e)) => log::error!("Error stopping backend services: {e}"),
            Err(_) => log::warn!("Backend services shutdown timed out"),
        }
    })
    .await;

    match cleanup_result {
        Ok(_) => log::debug!("All cleanup completed successfully"),
        Err(_) => log::warn!("Cleanup process timed out after 10 seconds"),
    }

    #[cfg(target_os = "windows")]
    {
        log::debug!("Waiting for Windows to clean up UI resources...");
        tokio::time::sleep(std::time::Duration::from_millis(500)).await;
    }

    log::debug!("Cleanup complete");
}

fn main() {
    let _ = fix_path_env::fix();
    init_process_monitoring();

    tauri::Builder::default()
        .plugin(tauri_plugin_updater::Builder::new().build())
        .plugin(tauri_plugin_opener::init())
        .plugin(tauri_plugin_single_instance::init(|app, _, _| {
            if let Some(window) = app.get_webview_window("main") {
                let _ = window.show();
                let _ = window.set_focus();
            }
        }))
        .plugin(tauri_plugin_fs::init())
        .plugin(tauri_plugin_shell::init())
        .plugin(tauri_plugin_persisted_scope::init())
        .plugin(tauri_plugin_log::Builder::new().clear_targets().target(tauri_plugin_log::Target::new(
            tauri_plugin_log::TargetKind::Stdout,
        )).target(tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Stderr)).build())
        .plugin(tauri_plugin_dialog::init())
        .manage(ProcessLogState(get_log_storage()))
        .manage(RunningProcesses::new())
        .manage(check_installation_on_startup())
        .invoke_handler(tauri::generate_handler![
            toggle_theme,
            navigate_to_page,
            save_working_directory,
            get_working_directory,
            get_home_directory,
            select_directory,
            get_installation_directory,
            get_userdata_directory,
            get_settings_directory,
            select_file,
            install_to_directory,
            check_directory_exists,
            check_file_exists,
            install_conda,
            abort_installation,
            get_installation_status,
            get_installation_state,
            setup_python_environment,
            create_environment,
            list_conda_environments,
            get_environment_extensions,
            install_extensions,
            update_extension,
            update_environment,
            update_installation_error,
            remove_extension,
            remove_environment,
            create_environment_from_requirements,
            select_requirements_file,
            execute_in_environment,
            start_jupyter_server,
            stop_jupyter_server,
            stop_all_jupyter_servers,
            check_jupyter_server,
            list_jupyter_servers,
            get_user_credentials,
            open_credentials_file,
            update_user_credentials,
            open_url_in_window,
            register_process_monitoring,
            unregister_process_monitoring,
            get_process_logs_history,
            clear_process_logs_history,
            open_jupyter_logs_window,
            update_jupyter_status,
            open_backend_logs_window,
            start_backend_service,
            stop_backend_service,
            update_backend_service,
            create_backend_service,
            delete_backend_service,
            list_backend_services,
            uninstall_application,
            quit_application,
            generate_self_signed_cert,
            update_openbb_settings,
            create_default_backend_services
        ])
        .setup(|app_handle| {
            let install_state = check_installation_on_startup();

            let show_after_update = {
                if let Ok(home_dir) = std::env::var("HOME").or_else(|_| std::env::var("USERPROFILE")) {
                    let flag_path = std::path::Path::new(&home_dir).join(".openbb_platform").join(".show_on_restart");
                    if flag_path.exists() {
                        log::info!("Found update restart flag - will show window");
                        let _ = std::fs::remove_file(&flag_path);
                        true
                    } else {
                        false
                    }
                } else {
                    false
                }
            };

            if install_state.is_installed {
                let backend_handle = app_handle.handle().clone();
                tauri::async_runtime::spawn(async move {
                    use crate::tauri_handlers::helpers::{RealFileExtTrait, RealFileSystem, RealEnvSystem};
                    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
                    log::debug!("Initializing backends after state setup delay");
                    if let Err(e) = initialize_backends(&backend_handle, RealFileSystem, RealEnvSystem, RealFileExtTrait).await {
                        log::error!("Failed to initialize backends: {e}");
                    }
                });
            }

            if let Some(window) = app_handle.get_webview_window("main") {
                window.set_menu(Menu::new(app_handle.handle())?)?;
            }

            let autostart_enabled = {
                #[cfg(target_os = "macos")]
                {
                    utils::autostart::macos_autostart::is_autostart_enabled(app_handle.handle()).unwrap_or(true)
                }
                #[cfg(target_os = "windows")]
                {
                    utils::autostart::windows_autostart::is_autostart_enabled(app_handle.handle()).unwrap_or(true)
                }
                #[cfg(target_os = "linux")]
                {
                    utils::autostart::linux_autostart::is_autostart_enabled(&app_handle.handle()).unwrap_or(true)
                }
            };
            log::debug!("Autostart is currently: {}", if autostart_enabled { "enabled" } else { "disabled" });

            let handle = app_handle.handle().clone();
            let open_item = MenuItemBuilder::new("Open Window").id("open").build(&handle)?;
            let open_workspace = MenuItemBuilder::new("Go to Workspace").id("open_workspace").build(&handle)?;
            let separator1 = tauri::menu::PredefinedMenuItem::separator(&handle)?;
            let open_environments_item = MenuItemBuilder::new("Environments").id("open_environments").build(&handle)?;
            let open_api_keys_item = MenuItemBuilder::new("API Keys").id("open_api_keys").build(&handle)?;
            let open_backends_item = MenuItemBuilder::new("Backends").id("open_backends").build(&handle)?;
            let separator2 = tauri::menu::PredefinedMenuItem::separator(&handle)?;
            let start_at_login_item = CheckMenuItemBuilder::new("Start at Login in Background")
                .id("start_at_login")
                .checked(autostart_enabled)
                .build(&handle)?;
            let separator3 = tauri::menu::PredefinedMenuItem::separator(&handle)?;
            let check_updates_item = MenuItemBuilder::new("Check for Updates").id("check_updates").build(&handle)?;
            let uninstall_item = MenuItemBuilder::new("Uninstall").id("uninstall").build(&handle)?;
            let quit_item = MenuItemBuilder::new("Quit").id("quit").build(&handle)?;

            let menu = Menu::with_items(&handle, &[
                &open_item,
                &open_workspace,
                &separator1,
                &open_backends_item,
                &open_environments_item,
                &open_api_keys_item,
                &separator2,
                &start_at_login_item,
                &separator3,
                &check_updates_item,
                &uninstall_item,
                &quit_item
            ])?;

            let icon = handle.default_window_icon().unwrap().clone();
            let tray_handle = handle.clone();
            let tray = TrayIconBuilder::new()
                .icon(icon)
                .tooltip("Open Data Platform - By OpenBB")
                .menu(&menu)
                .on_menu_event(move |_tray, event| {
                    let id_string = event.id().0.as_str();
                      match id_string {
                        "quit" => {
                            log::debug!("Received termination signal, running cleanup...");
                            let rt = tokio::runtime::Runtime::new().unwrap();
                            let cleanup_handle = tray_handle.clone();
                            rt.block_on(async {
                                cleanup_all_processes(cleanup_handle).await;
                            });
                            log::debug!("Exiting application");
                            tray_handle.exit(0);
                        }
                        "open" => {
                            if let Some(window) = tray_handle.get_webview_window("main") {
                                window.show().unwrap();
                                window.set_focus().unwrap();
                            }
                        }
                        "open_workspace" => open_workspace_in_browser(),
                        "open_environments" => navigate_to_page(tray_handle.clone(), "/environments"),
                        "open_api_keys" => navigate_to_page(tray_handle.clone(), "/api-keys"),
                        "open_backends" => navigate_to_page(tray_handle.clone(), "/backends"),
                        "check_updates" => {
                            let update_handle = tray_handle.clone();
                            tauri::async_runtime::spawn(async move {
                                trigger_update_dialog(update_handle).await;
                            });
                        }
                        "uninstall" => {
                            if let Some(window) = tray_handle.get_webview_window("main") {
                                window.show().unwrap();
                                window.set_focus().unwrap();
                                let install_state = check_installation_on_startup();
                                if !install_state.is_installed {
                                    tray_handle.dialog().message("The installation appears to be incomplete. To uninstall, quit the application and remove the application from the operating system.").kind(tauri_plugin_dialog::MessageDialogKind::Error).show(|_| {});
                                } else {
                                    window.eval("window.location.href = '/uninstall';").unwrap();
                                }
                            }
                        },
                        "start_at_login" => {
                            let app_handle = tray_handle.clone();
                            let is_enabled = {
                                #[cfg(target_os = "macos")]
                                {
                                    utils::autostart::macos_autostart::is_autostart_enabled(&app_handle).unwrap_or(false)
                                }
                                #[cfg(target_os = "windows")]
                                {
                                    utils::autostart::windows_autostart::is_autostart_enabled(&app_handle).unwrap_or(false)
                                }
                                #[cfg(target_os = "linux")]
                                {
                                    utils::autostart::linux_autostart::is_autostart_enabled(&app_handle).unwrap_or(false)
                                }
                            };
                            log::debug!("Current autostart status: {}", if is_enabled { "enabled" } else { "disabled" });
                            let target_state = !is_enabled;
                            log::debug!("Attempting to {} autostart", if target_state { "enable" } else { "disable" });
                            let result = {
                                #[cfg(target_os = "macos")]
                                {
                                    if target_state {
                                        utils::autostart::macos_autostart::enable_autostart(&app_handle)
                                    } else {
                                        utils::autostart::macos_autostart::disable_autostart(&app_handle)
                                    }
                                }
                                #[cfg(target_os = "windows")]
                                {
                                    if target_state {
                                        utils::autostart::windows_autostart::enable_autostart(&app_handle)
                                    } else {
                                        utils::autostart::windows_autostart::disable_autostart(&app_handle)
                                    }
                                }
                                #[cfg(target_os = "linux")]
                                {
                                    if target_state {
                                        utils::autostart::linux_autostart::enable_autostart(&app_handle)
                                    } else {
                                        utils::autostart::linux_autostart::disable_autostart(&app_handle)
                                    }
                                }
                            };
                            if let Err(e) = result {
                                log::error!("Failed to {} autostart: {}", if target_state { "enable" } else { "disable" }, e);
                                return;
                            }
                            if let Err(e) = start_at_login_item.set_checked(target_state) {
                                log::error!("Failed to update menu item state: {e}");
                            } else {
                                log::debug!("Menu item state updated to: {target_state}");
                            }
                            log::debug!("Successfully {} autostart", if target_state { "enabled" } else { "disabled" });
                        }
                        _ => {}
                    }
                })
                .build(&handle)
                .unwrap();

            app_handle.manage(tray);

            if let Some(window) = app_handle.get_webview_window("main") {
                let window_clone = window.clone();
                window.on_window_event(move |event| {
                    if let tauri::WindowEvent::CloseRequested { api, .. } = event {
                        window_clone.hide().unwrap();
                        api.prevent_close();
                    }
                });
                #[cfg(target_os = "macos")]
                {
                    use objc2_app_kit::{NSColor, NSWindow};
                    let ns_window_ptr = window.ns_window().unwrap();
                    let ns_window = unsafe { &*(ns_window_ptr as *mut NSWindow) };
                    let bg_color = NSColor::colorWithRed_green_blue_alpha(0.0, 0.0, 0.0, 1.0);
                    ns_window.setBackgroundColor(Some(&bg_color));
                };
            }

            let exit_handle = app_handle.handle().clone();
            ctrlc::set_handler(move || {
                println!("Received termination signal, running cleanup...");
                let rt = tokio::runtime::Runtime::new().unwrap();
                let cleanup_handle = exit_handle.clone();
                rt.block_on(async {
                    cleanup_all_processes(cleanup_handle).await;
                });
                exit_handle.exit(0);
            }).unwrap_or_else(|e| log::error!("Error setting Ctrl-C handler: {e}"));

            #[cfg(target_os = "macos")]
            {
                let termination_handle = app_handle.handle().clone();
                utils::app_termination::setup_termination_handler(termination_handle);
            }

            if !install_state.is_installed {
                log::info!("Installation is INVALID - showing window and navigating to setup");
                if let Some(window) = handle.get_webview_window("main") {
                    let _ = window.show();
                    let _ = window.set_focus();
                    let _ = window.eval("localStorage.clear(); console.log('localStorage cleared due to INVALID installation');");
                    let _ = window.eval("window.location.href = '/setup'");
                }
            } else {
                // VALID INSTALLATION
                log::info!("Installation is VALID");

                let update_handle = handle.clone();
                tauri::async_runtime::spawn(async move {
                    log::debug!("Starting background update check...");
                    tokio::time::sleep(std::time::Duration::from_secs(3)).await;
                    background_update_check(update_handle).await;
                });

                if let Some(window) = handle.get_webview_window("main") {
                    let _ = window.eval("localStorage.setItem('environments-first-load-done', 'true');");

                    if show_after_update {
                        log::info!("SHOWING WINDOW AFTER UPDATE RESTART");
                        let _ = window.show();
                    }

                    let _ = window.set_focus();
                }
            }
            Ok(())
        })
        .build(tauri::generate_context!())
        .unwrap_or_else(|e| {
            log::error!("Error while building Tauri application: {e}");
            std::process::exit(1);
        })
        .run(|app_handle, event| {
            let is_restart_requested = Arc::new(AtomicBool::new(false));
            let is_restart_requested_clone = is_restart_requested.clone();

            if let tauri::RunEvent::ExitRequested { code, ..} = event
                && code.unwrap() == RESTART_EXIT_CODE {
                    is_restart_requested.store(true, Ordering::SeqCst);
                }

            if let tauri::RunEvent::ExitRequested { ref api, .. } = event {
                log::debug!("Caught applicationWillTerminate event, running cleanup...");
                api.prevent_exit();
                let rt = tokio::runtime::Runtime::new().unwrap();
                let cleanup_handle = app_handle.clone();
                rt.block_on(async {
                    cleanup_all_processes(cleanup_handle).await;
                });
                if is_restart_requested_clone.load(Ordering::SeqCst) {
                    log::debug!("Restart requested, exiting with restart code");
                    tauri::process::restart(&app_handle.env());
                } else {
                    log::debug!("Exiting application normally");
                    std::process::exit(0);
                }
            }

            #[cfg(target_os = "macos")]
            {
            if let tauri::RunEvent::Reopen { .. } = event
                && let Some(window) = app_handle.get_webview_window("main") {
                    let _ = window.show();
                    let _ = window.set_focus();
                }
            }

            if let tauri::RunEvent::Exit = event
                && is_restart_requested_clone.load(Ordering::SeqCst) {
                    app_handle.cleanup_before_exit();
                    let env = app_handle.env();
                    tauri::process::restart(&env);
                }
        });
}
