// Integration coverage for client app runtime startup paths.
//
// Scope: launch the real `lesavka-client` binary with runtime toggles that
// execute `LesavkaClientApp::run` startup branches.
// Targets: `client/src/app.rs`.
// Why: process-level startup behavior should stay deterministic in both
// headless and desktop-style launches.

use serial_test::serial;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::{Duration, Instant};
use tempfile::tempdir;

fn candidate_dirs() -> Vec<PathBuf> {
    let exe = std::env::current_exe().expect("current exe path");
    let mut dirs = Vec::new();
    if let Some(parent) = exe.parent() {
        dirs.push(parent.to_path_buf());
        if let Some(grand) = parent.parent() {
            dirs.push(grand.to_path_buf());
        }
    }
    dirs.push(PathBuf::from("target/debug"));
    dirs.push(PathBuf::from("target/llvm-cov-target/debug"));
    dirs
}

fn find_binary(name: &str) -> Option<PathBuf> {
    candidate_dirs()
        .into_iter()
        .map(|dir| dir.join(name))
        .find(|path| path.exists() && path.is_file())
}

fn wait_for_exit(
    mut child: std::process::Child,
    timeout: Duration,
) -> Option<std::process::ExitStatus> {
    let deadline = Instant::now() + timeout;
    loop {
        if let Some(status) = child.try_wait().expect("poll child") {
            return Some(status);
        }
        if Instant::now() >= deadline {
            let _ = child.kill();
            let _ = child.wait();
            return None;
        }
        std::thread::sleep(Duration::from_millis(50));
    }
}

#[test]
#[serial]
fn client_headless_runtime_enters_main_loop() {
    let Some(bin) = find_binary("lesavka-client") else {
        return;
    };

    let child = Command::new(Path::new(&bin))
        .arg("--no-launcher")
        .env("LESAVKA_HEADLESS", "1")
        .env("LESAVKA_SERVER_ADDR", "http://127.0.0.1:9")
        .spawn()
        .expect("spawn lesavka-client");

    if let Some(status) = wait_for_exit(child, Duration::from_millis(900)) {
        assert!(
            !status.success(),
            "headless runtime unexpectedly exited successfully"
        );
    }
}

#[test]
#[serial]
fn client_desktop_runtime_executes_startup_branches() {
    let Some(bin) = find_binary("lesavka-client") else {
        return;
    };

    let runtime_dir = tempdir().expect("runtime dir");
    let child = Command::new(Path::new(&bin))
        .arg("--no-launcher")
        .env("XDG_RUNTIME_DIR", runtime_dir.path())
        .env_remove("LESAVKA_HEADLESS")
        .env("LESAVKA_SERVER_ADDR", "not a uri")
        .spawn()
        .expect("spawn lesavka-client");

    if let Some(status) = wait_for_exit(child, Duration::from_secs(3)) {
        assert!(
            !status.success(),
            "desktop runtime unexpectedly exited successfully"
        );
    }
}
