// Chaos contract for interrupted or partially failed installs.
//
// Scope: preserve best-effort cleanup and explicit recovery boundaries in
// install scripts without executing privileged operations.
// Targets: client/server install scripts.
// Why: failed installs should leave the Pi and desktop in a recoverable state,
// especially around capture power, temporary PKI material, and USB gadget reset.

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

#[test]
fn server_restores_capture_power_after_discovery_failures() {
    for marker in [
        "trap restore_capture_power_after_discovery EXIT",
        "restore_capture_power_after_discovery",
        "borrowing relay GPIO power for capture discovery",
        "trap - EXIT",
    ] {
        assert!(
            SERVER_INSTALL.contains(marker),
            "server install should preserve capture-power recovery marker {marker}"
        );
    }
}

#[test]
fn attached_host_gadget_rebuilds_require_two_explicit_knobs() {
    for marker in [
        "LESAVKA_FORCE_GADGET_REBUILD",
        "LESAVKA_ALLOW_GADGET_RESET",
        "EXPLICIT_GADGET_REBUILD=1",
        "Preserving the attached gadget to avoid wedging the Pi USB controller",
        "Run during a maintenance window",
    ] {
        assert!(
            SERVER_INSTALL.contains(marker),
            "server install should preserve attached-gadget safety marker {marker}"
        );
    }
}

#[test]
fn client_tls_bundle_tempfiles_are_removed_on_failure_and_success() {
    for marker in [
        "tmp_bundle=$(run_as_user mktemp",
        "rm -f \"$tmp_bundle\"",
        "tmp=$(mktemp -d)",
        "sudo rm -rf \"$tmp\"",
        "rm -f \"$bundle\"",
    ] {
        assert!(
            CLIENT_INSTALL.contains(marker),
            "client install should preserve temporary bundle cleanup marker {marker}"
        );
    }
}

#[test]
fn server_install_refuses_to_kill_unrelated_port_owners() {
    for marker in [
        "unexpected process",
        "no owning PID could be identified",
        "refusing to start a duplicate server",
        "clear_stale_server_listener",
    ] {
        assert!(
            SERVER_INSTALL.contains(marker),
            "stale listener cleanup should preserve fail-safe marker {marker}"
        );
    }
}

#[test]
fn installers_refuse_to_replace_live_entrypoints_with_empty_artifacts() {
    for marker in [
        "install_verified_executable()",
        "source '$src' is missing or empty",
        "staged install output was not a non-empty executable",
        "Preserving the existing installed executable",
    ] {
        assert!(
            SERVER_INSTALL.contains(marker),
            "server installer should preserve verified executable install marker {marker}"
        );
        assert!(
            CLIENT_INSTALL.contains(marker),
            "client installer should preserve verified executable install marker {marker}"
        );
    }

    for marker in [
        "install_verified_executable \"$SRC_DIR/target/release/lesavka-server\" /usr/local/bin/lesavka-server",
        "install_verified_executable \"$SRC_DIR/target/release/lesavka-uvc\" /usr/local/bin/lesavka-uvc",
        "install_verified_executable \"$SRC_DIR/scripts/daemon/lesavka-core.sh\" /usr/local/bin/lesavka-core.sh",
        "install_verified_executable \"$SRC_DIR/scripts/daemon/lesavka-uvc.sh\" /usr/local/bin/lesavka-uvc.sh",
        "install_verified_executable \"$SRC_DIR/scripts/daemon/lesavka-recovery-ladder.sh\" /usr/local/bin/lesavka-recovery-ladder",
    ] {
        assert!(
            SERVER_INSTALL.contains(marker),
            "server installer should protect systemd entrypoint {marker}"
        );
    }

    assert!(
        CLIENT_INSTALL.contains(
            "install_verified_executable \"$SRC/target/release/lesavka-client\" /usr/local/bin/lesavka-client"
        ),
        "client installer should protect the launchable desktop binary"
    );
}

#[test]
fn recovery_ladder_restores_before_rebooting_or_touching_the_core_gadget() {
    let ladder = include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/scripts/daemon/lesavka-recovery-ladder.sh"
    ));
    for marker in [
        "restore_last_good",
        "restart_server_only",
        "restart_uvc_and_server",
        "LESAVKA_RECOVERY_ALLOW_UVC_RESTART:-0",
        "LESAVKA_RECOVERY_ALLOW_CORE_RESTART:-0",
        "LESAVKA_RECOVERY_ALLOW_REBOOT:-0",
        "UVC helper restart disabled; preserving attached USB gadget",
        "core restart disabled; preserving attached USB gadget",
        "reboot disabled; leaving host online for operator inspection",
    ] {
        assert!(
            ladder.contains(marker),
            "recovery ladder should preserve soft-recovery marker {marker}"
        );
    }
    assert!(
        ladder.find("restore_last_good").unwrap() < ladder.find("reboot_if_allowed").unwrap(),
        "the ladder should try last-known-good restore before any optional reboot"
    );
}
