// Contract tests for client install-time security defaults.
//
// Scope: inspect the client installer shell contract without running it.
// Targets: `scripts/install/client.sh`.
// Why: secure-by-default relay transport depends on installing the server-issued
// client cert bundle exactly where the desktop app auto-discovers it.

const CLIENT_INSTALL: &str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/scripts/install/client.sh"
));

#[test]
fn client_install_accepts_server_generated_tls_bundle() {
    for expected in [
        "LESAVKA_CLIENT_PKI_BUNDLE",
        "CLIENT_PKI_DIR",
        "ca.crt",
        "client.crt",
        "client.key",
        "paste-key",
        "install_client_pki_bundle",
        "fetch_client_pki_bundle",
        "LESAVKA_CLIENT_PKI_SSH_SOURCE",
        "CLIENT_PASTE_KEY_FILE",
        "LESAVKA_CLIENT_CAPTURE_DIR",
        "theia:/etc/lesavka/lesavka-client-pki.tar.gz",
        "Pictures/lesavka",
        "HTTPS/mTLS relay connections will not work until this bundle is installed",
        "encrypted paste key:",
        "TLS identity:",
        "Paste key:",
        "Captures:",
        "$USER_HOME/.local/bin/lesavka-client",
        "User PATH alias:",
    ] {
        assert!(
            CLIENT_INSTALL.contains(expected),
            "client installer should include TLS bundle contract fragment {expected}"
        );
    }
    assert!(
        CLIENT_INSTALL.contains(".config/lesavka/pki"),
        "client cert bundle should land in the same path the desktop app auto-loads"
    );
    assert!(
        CLIENT_INSTALL.contains(".config/lesavka/paste-key"),
        "client installer should land the server-issued paste key where runtime paste auto-loads it"
    );
    assert!(
        CLIENT_INSTALL.contains("0600"),
        "client private key should be installed with private permissions"
    );
    assert!(
        CLIENT_INSTALL.contains("scp -q -o BatchMode=yes"),
        "client installer should auto-fetch the server enrollment bundle without hanging"
    );
    assert!(
        CLIENT_INSTALL.contains("run_as_user mktemp"),
        "auto-fetch destination should be owned by the user who runs scp"
    );
}

#[test]
fn client_install_prefers_invoked_checkout_for_development_installs() {
    for expected in [
        "INSTALL_SOURCE=${LESAVKA_INSTALL_SOURCE:-auto}",
        "resolve_source_checkout",
        "Using local source checkout",
        "set LESAVKA_INSTALL_SOURCE=ref",
        "LESAVKA_INSTALL_SOURCE=local requested",
        "unsupported LESAVKA_INSTALL_SOURCE",
        "source_revision",
        "+dirty",
    ] {
        assert!(
            CLIENT_INSTALL.contains(expected),
            "client installer should preserve local-source install marker {expected}"
        );
    }
    assert!(
        CLIENT_INSTALL.find("resolve_source_checkout").unwrap()
            < CLIENT_INSTALL
                .find("cargo clean && cargo build --release")
                .unwrap(),
        "client installer should resolve source before building"
    );
}

#[test]
fn client_install_reports_nvidia_and_open_source_media_routes() {
    for expected in [
        "report_client_media_acceleration",
        "refresh_gstreamer_registry_cache",
        "warn_running_stale_client_processes",
        "Refreshing GStreamer plugin registry",
        "Lesavka is still running from an older/deleted binary.",
        "Close and relaunch Lesavka before judging video/audio performance",
        "run_as_user rm -f \"$USER_HOME/.cache/gstreamer-1.0\"/registry.*",
        "gst-inspect-1.0 nvcodec",
        "gst-inspect-1.0 va",
        "gst_element_available",
        "first_available_gst_element",
        "nvidia-smi is available",
        "NVIDIA nvcodec is installed but CUDA initialization failed",
        "FFmpeg hevc_nvenc encoded a probe frame",
        "ffmpeg_hevc_nvenc_usable",
        "/dev/nvidiactl",
        "proprietary NVIDIA GStreamer route",
        "Vulkan/VAAPI/V4L2 GStreamer route",
        "nvh265enc",
        "nvautogpuh265enc",
        "nvh265dec",
        "nvh264enc",
        "nvautogpuh264enc",
        "nvh264dec",
        "nvh264sldec",
        "vah264enc",
        "vulkanh264enc",
        "vulkanh264dec",
        "vulkanh265dec",
        "gst-plugin-va",
        "intel-media-driver",
        "vah265enc",
        "vaapih265enc",
        "v4l2h265enc",
        "ffmpeg",
        "hevc_nvenc",
        "vah264dec",
        "vaapih264dec",
        "v4l2h264dec",
        "v4l2slh264dec",
        "upstream H.264 hardware encoder candidate",
        "downstream H.264 hardware decoder candidate",
        "will fail instead of using x265enc",
        "will fail instead of using x264enc",
        "will fail instead of using decodebin",
        "opusenc",
        "opusdec",
        "Opus upstream audio transport route",
        "microphone noise suppression route",
        "webrtcdsp",
        "fall back to PCM",
    ] {
        assert!(
            CLIENT_INSTALL.contains(expected),
            "client installer should preserve media acceleration fragment {expected}"
        );
    }
    assert!(
        CLIENT_INSTALL
            .find("require_gst_element pipewiresrc")
            .unwrap()
            < CLIENT_INSTALL
                .rfind("report_client_media_acceleration")
                .unwrap(),
        "media acceleration reporting should run after baseline GStreamer tools are verified"
    );
}

#[test]
fn client_install_accepts_required_modules_already_loaded_by_the_running_kernel() {
    assert!(
        CLIENT_INSTALL.contains("[[ -d \"/sys/module/${module}\" ]] || modinfo"),
        "installer should not reject a working loaded module just because a newer package replaced the running kernel's module tree"
    );
}

#[test]
fn client_install_treats_pipewire_as_one_coherent_transaction() {
    for expected in [
        "pacman_install()",
        "pipewire_package_set()",
        "libpipewire pipewire pipewire-audio pipewire-pulse",
        "for package in pipewire-alsa pipewire-jack",
        "pacman -Q \"$package\"",
        "\"${PIPEWIRE_PACKAGES[@]}\"",
        "breaks dependency '.*pipewire",
        "PipeWire packages are at mixed exact versions",
        "Lesavka does not require JACK",
        "do not remove jack2 just for Lesavka",
        "sudo pacman -Syu",
        "failed retrieving file",
        "sudo pacman -Syu --disable-download-timeout",
    ] {
        assert!(
            CLIENT_INSTALL.contains(expected),
            "client installer should preserve PipeWire transaction marker {expected}"
        );
    }
    assert!(
        !CLIENT_INSTALL.contains("sudo pacman -Sq --needed --noconfirm \\\n  git"),
        "base package install should flow through pacman_install so failures get actionable diagnostics"
    );
}
