use tsafe_core::agent::{
    agent_sock_path, format_agent_sock, read_agent_sock, request_password_from_agent, send_lock,
    write_agent_sock, ENV_AGENT_SOCK,
};

#[test]
fn request_password_from_agent_clears_stale_state_file_when_agent_is_unreachable() {
    let temp = tempfile::tempdir().unwrap();
    let vault_dir = temp.path().join("vaults");
    let dead_pipe = dead_agent_pipe_name(&temp);

    temp_env::with_var(
        "TSAFE_VAULT_DIR",
        Some(vault_dir.as_os_str().to_str().unwrap()),
        || {
            temp_env::with_var(ENV_AGENT_SOCK, None::<&str>, || {
                let stale_sock = format_agent_sock(&dead_pipe, "deadbeef");
                write_agent_sock(&stale_sock);

                assert_eq!(read_agent_sock().as_deref(), Some(stale_sock.as_str()));
                assert!(agent_sock_path().exists());

                let password = request_password_from_agent("default").unwrap();

                assert!(password.is_none());
                assert!(read_agent_sock().is_none());
                assert!(
                    !agent_sock_path().exists(),
                    "stale persisted agent state should be removed after a failed connect"
                );
            });
        },
    );
}

#[test]
fn request_password_from_agent_clears_malformed_persisted_state_file() {
    let temp = tempfile::tempdir().unwrap();
    let vault_dir = temp.path().join("vaults");

    temp_env::with_var(
        "TSAFE_VAULT_DIR",
        Some(vault_dir.as_os_str().to_str().unwrap()),
        || {
            temp_env::with_var(ENV_AGENT_SOCK, None::<&str>, || {
                write_agent_sock("not-a-valid-agent-sock");

                let err = request_password_from_agent("default").unwrap_err();

                assert!(
                    err.to_string().contains("malformed TSAFE_AGENT_SOCK"),
                    "unexpected error: {err}"
                );
                assert!(read_agent_sock().is_none());
                assert!(
                    !agent_sock_path().exists(),
                    "malformed persisted agent state should be removed after parse failure"
                );
            });
        },
    );
}

#[test]
fn send_lock_clears_stale_state_file_when_agent_is_unreachable() {
    let temp = tempfile::tempdir().unwrap();
    let vault_dir = temp.path().join("vaults");
    let dead_pipe = dead_agent_pipe_name(&temp);

    temp_env::with_var(
        "TSAFE_VAULT_DIR",
        Some(vault_dir.as_os_str().to_str().unwrap()),
        || {
            temp_env::with_var(ENV_AGENT_SOCK, None::<&str>, || {
                let stale_sock = format_agent_sock(&dead_pipe, "deadbeef");
                write_agent_sock(&stale_sock);

                assert_eq!(read_agent_sock().as_deref(), Some(stale_sock.as_str()));
                assert!(agent_sock_path().exists());

                send_lock().unwrap();

                assert!(read_agent_sock().is_none());
                assert!(
                    !agent_sock_path().exists(),
                    "stale persisted agent state should be removed after a failed lock connect"
                );
            });
        },
    );
}

#[test]
fn explicit_malformed_agent_sock_env_does_not_clear_persisted_fallback_state() {
    let temp = tempfile::tempdir().unwrap();
    let vault_dir = temp.path().join("vaults");
    let fallback_sock = format_agent_sock(&dead_agent_pipe_name(&temp), "deadbeef");

    temp_env::with_var(
        "TSAFE_VAULT_DIR",
        Some(vault_dir.as_os_str().to_str().unwrap()),
        || {
            write_agent_sock(&fallback_sock);

            temp_env::with_var(ENV_AGENT_SOCK, Some("malformed-env-value"), || {
                let err = request_password_from_agent("default").unwrap_err();

                assert!(
                    err.to_string().contains("malformed TSAFE_AGENT_SOCK"),
                    "unexpected error: {err}"
                );
                assert_eq!(read_agent_sock().as_deref(), Some(fallback_sock.as_str()));
                assert!(
                    agent_sock_path().exists(),
                    "an explicit env override should not delete the persisted fallback state"
                );
            });
        },
    );
}

#[cfg(target_os = "windows")]
fn dead_agent_pipe_name(temp: &tempfile::TempDir) -> String {
    format!(
        r"\\.\pipe\tsafe-agent-stale-test-{}-{}",
        std::process::id(),
        temp.path().display()
    )
}

#[cfg(not(target_os = "windows"))]
fn dead_agent_pipe_name(temp: &tempfile::TempDir) -> String {
    temp.path()
        .join("no-agent.sock")
        .to_string_lossy()
        .into_owned()
}
