use super::super::protocol::RemoteControlPairingStatusRequest;
use super::super::protocol::StartRemoteControlPairingRequest;
use super::*;
use codex_login::AuthKeyringBackendKind;
use pretty_assertions::assert_eq;
use std::io;

fn remote_control_enrollment(
    remote_control_url: &str,
    remote_control_token: &str,
) -> RemoteControlEnrollment {
    RemoteControlEnrollment {
        remote_control_target: normalize_remote_control_url(remote_control_url)
            .expect("target should normalize"),
        account_id: "account-id".to_string(),
        environment_id: "environment-id".to_string(),
        server_id: "server-id".to_string(),
        server_name: "server-name".to_string(),
        remote_control_token: Some(remote_control_token.to_string()),
        expires_at: Some(
            OffsetDateTime::from_unix_timestamp(33_336_362_096)
                .expect("future timestamp should parse"),
        ),
    }
}

async fn pairing_error(status: &'static str, body: &'static str) -> (String, String) {
    let listener = TcpListener::bind("127.0.0.1:0")
        .await
        .expect("listener should bind");
    let remote_control_url = remote_control_url_for_listener(&listener);
    let expected_pair_url = normalize_remote_control_url(&remote_control_url)
        .expect("target should normalize")
        .pair_url;
    let server_task = tokio::spawn(async move {
        let pairing_request = accept_http_request(&listener).await;
        respond_with_status_and_headers(
            pairing_request.stream,
            status,
            &[("x-request-id", "request-123"), ("cf-ray", "ray-123")],
            body,
        )
        .await;
    });

    let err = remote_control_enrollment(&remote_control_url, "remote-control-token")
        .start_pairing(StartRemoteControlPairingRequest { manual_code: false })
        .await
        .expect_err("pairing should fail");
    server_task.await.expect("server task should finish");
    (err.to_string(), expected_pair_url)
}

async fn pairing_response_error(body: serde_json::Value) -> String {
    let listener = TcpListener::bind("127.0.0.1:0")
        .await
        .expect("listener should bind");
    let remote_control_url = remote_control_url_for_listener(&listener);
    let server_task = tokio::spawn(async move {
        let pairing_request = accept_http_request(&listener).await;
        respond_with_json(pairing_request.stream, body).await;
    });

    let err = remote_control_enrollment(&remote_control_url, "remote-control-token")
        .start_pairing(StartRemoteControlPairingRequest { manual_code: false })
        .await
        .expect_err("pairing should fail");
    server_task.await.expect("server task should finish");
    err.to_string()
}

async fn pairing_status_error(status: &'static str, body: &'static str) -> (io::Error, String) {
    let listener = TcpListener::bind("127.0.0.1:0")
        .await
        .expect("listener should bind");
    let remote_control_url = remote_control_url_for_listener(&listener);
    let expected_status_url = normalize_remote_control_url(&remote_control_url)
        .expect("target should normalize")
        .pair_status_url;
    let server_task = tokio::spawn(async move {
        let status_request = accept_http_request(&listener).await;
        respond_with_status_and_headers(
            status_request.stream,
            status,
            &[("x-request-id", "request-123"), ("cf-ray", "ray-123")],
            body,
        )
        .await;
    });

    let err = remote_control_enrollment(&remote_control_url, "remote-control-token")
        .pairing_status(RemoteControlPairingStatusRequest {
            pairing_code: Some("pairing-code".to_string()),
            manual_pairing_code: None,
        })
        .await
        .expect_err("pairing status should fail");
    server_task.await.expect("server task should finish");
    (err, expected_status_url)
}

#[tokio::test]
async fn remote_control_handle_starts_pairing_before_websocket_connects() {
    let listener = TcpListener::bind("127.0.0.1:0")
        .await
        .expect("listener should bind");
    let remote_control_url = remote_control_url_for_listener(&listener);
    let server_task = tokio::spawn(async move {
        let refresh_request = accept_http_request(&listener).await;
        assert_eq!(
            refresh_request.request_line,
            "POST /backend-api/wham/remote/control/server/refresh HTTP/1.1"
        );
        assert_eq!(
            serde_json::from_str::<serde_json::Value>(&refresh_request.body)
                .expect("refresh request body should deserialize"),
            json!({
                "server_id": "srv_e_test",
                "installation_id": TEST_INSTALLATION_ID,
            })
        );
        respond_with_json(
            refresh_request.stream,
            remote_control_server_token_response(
                "srv_e_test",
                "env_test",
                TEST_REFRESHED_REMOTE_CONTROL_SERVER_TOKEN,
            ),
        )
        .await;

        let pairing_request = accept_http_request(&listener).await;
        assert_eq!(
            pairing_request.request_line,
            "POST /backend-api/wham/remote/control/server/pair HTTP/1.1"
        );
        assert_eq!(
            pairing_request.headers.get("authorization"),
            Some(&format!(
                "Bearer {TEST_REFRESHED_REMOTE_CONTROL_SERVER_TOKEN}"
            ))
        );
        assert_eq!(
            serde_json::from_str::<serde_json::Value>(&pairing_request.body)
                .expect("pairing request body should deserialize"),
            json!({ "manual_code": true })
        );
        respond_with_json(
            pairing_request.stream,
            json!({
                "pairing_code": "pairing-code",
                "manual_pairing_code": "ABCD-EFGH",
                "server_id": "srv_e_test",
                "environment_id": "env_test",
                "expires_at": "3026-05-22T12:34:56Z",
            }),
        )
        .await;
    });
    let remote_handle = remote_control_handle_with_current_enrollment(
        &remote_control_url,
        remote_control_auth_manager(),
    );
    remote_handle
        .current_enrollment
        .lock()
        .await
        .as_mut()
        .expect("current enrollment should exist")
        .expires_at = Some(OffsetDateTime::now_utc() + time::Duration::seconds(29));

    let response = remote_handle
        .start_pairing(
            RemoteControlPairingStartParams { manual_code: true },
            /*app_server_client_name*/ None,
        )
        .await
        .expect("pairing should use the current server before websocket connect");
    server_task.await.expect("server task should finish");

    assert_eq!(
        response,
        RemoteControlPairingStartResponse {
            pairing_code: "pairing-code".to_string(),
            manual_pairing_code: Some("ABCD-EFGH".to_string()),
            environment_id: "env_test".to_string(),
            expires_at: 33_336_362_096,
        }
    );
}

#[tokio::test]
async fn remote_control_pairing_status_returns_pending() {
    let listener = TcpListener::bind("127.0.0.1:0")
        .await
        .expect("listener should bind");
    let remote_control_url = remote_control_url_for_listener(&listener);
    let server_task = tokio::spawn(async move {
        let status_request = accept_http_request(&listener).await;
        assert_eq!(
            status_request.request_line,
            "POST /backend-api/wham/remote/control/server/pair/status HTTP/1.1"
        );
        assert_eq!(
            status_request.headers.get("authorization"),
            Some(&"Bearer remote-control-token".to_string())
        );
        assert_eq!(
            serde_json::from_str::<serde_json::Value>(&status_request.body)
                .expect("status request body should deserialize"),
            json!({ "pairing_code": "pairing-code" })
        );
        respond_with_json(status_request.stream, json!({ "claimed": false })).await;
    });

    let response = remote_control_enrollment(&remote_control_url, "remote-control-token")
        .pairing_status(RemoteControlPairingStatusRequest {
            pairing_code: Some("pairing-code".to_string()),
            manual_pairing_code: None,
        })
        .await
        .expect("pairing status should succeed");
    server_task.await.expect("server task should finish");

    assert!(!response.claimed);
}

#[tokio::test]
async fn remote_control_pairing_status_accepts_manual_pairing_code() {
    let listener = TcpListener::bind("127.0.0.1:0")
        .await
        .expect("listener should bind");
    let remote_control_url = remote_control_url_for_listener(&listener);
    let server_task = tokio::spawn(async move {
        let status_request = accept_http_request(&listener).await;
        assert_eq!(
            status_request.request_line,
            "POST /backend-api/wham/remote/control/server/pair/status HTTP/1.1"
        );
        assert_eq!(
            serde_json::from_str::<serde_json::Value>(&status_request.body)
                .expect("status request body should deserialize"),
            json!({ "manual_pairing_code": "ABCD-EFGH" })
        );
        respond_with_json(status_request.stream, json!({ "claimed": false })).await;
    });

    let response = remote_control_enrollment(&remote_control_url, "remote-control-token")
        .pairing_status(RemoteControlPairingStatusRequest {
            pairing_code: None,
            manual_pairing_code: Some("ABCD-EFGH".to_string()),
        })
        .await
        .expect("pairing status should succeed");
    server_task.await.expect("server task should finish");

    assert!(!response.claimed);
}

#[tokio::test]
async fn remote_control_pairing_status_returns_claimed() {
    let listener = TcpListener::bind("127.0.0.1:0")
        .await
        .expect("listener should bind");
    let remote_control_url = remote_control_url_for_listener(&listener);
    let server_task = tokio::spawn(async move {
        let status_request = accept_http_request(&listener).await;
        assert_eq!(
            status_request.request_line,
            "POST /backend-api/wham/remote/control/server/pair/status HTTP/1.1"
        );
        respond_with_json(status_request.stream, json!({ "claimed": true })).await;
    });

    let response = remote_control_enrollment(&remote_control_url, "remote-control-token")
        .pairing_status(RemoteControlPairingStatusRequest {
            pairing_code: Some("pairing-code".to_string()),
            manual_pairing_code: None,
        })
        .await
        .expect("pairing status should succeed");
    server_task.await.expect("server task should finish");

    assert!(response.claimed);
}

#[tokio::test]
async fn remote_control_handle_refreshes_after_pairing_status_auth_failure() {
    let listener = TcpListener::bind("127.0.0.1:0")
        .await
        .expect("listener should bind");
    let remote_control_url = remote_control_url_for_listener(&listener);
    let server_task = tokio::spawn(async move {
        let stale_status_request = accept_http_request(&listener).await;
        assert_eq!(
            stale_status_request.request_line,
            "POST /backend-api/wham/remote/control/server/pair/status HTTP/1.1"
        );
        assert_eq!(
            stale_status_request.headers.get("authorization"),
            Some(&format!("Bearer {TEST_REMOTE_CONTROL_SERVER_TOKEN}"))
        );
        respond_with_status(stale_status_request.stream, "401 Unauthorized", "").await;

        let refresh_request = accept_http_request(&listener).await;
        assert_eq!(
            refresh_request.request_line,
            "POST /backend-api/wham/remote/control/server/refresh HTTP/1.1"
        );
        respond_with_json(
            refresh_request.stream,
            remote_control_server_token_response(
                "srv_e_test",
                "env_test",
                TEST_REFRESHED_REMOTE_CONTROL_SERVER_TOKEN,
            ),
        )
        .await;

        let refreshed_status_request = accept_http_request(&listener).await;
        assert_eq!(
            refreshed_status_request.request_line,
            "POST /backend-api/wham/remote/control/server/pair/status HTTP/1.1"
        );
        assert_eq!(
            refreshed_status_request.headers.get("authorization"),
            Some(&format!(
                "Bearer {TEST_REFRESHED_REMOTE_CONTROL_SERVER_TOKEN}"
            ))
        );
        respond_with_json(refreshed_status_request.stream, json!({ "claimed": true })).await;
    });
    let remote_handle = remote_control_handle_with_current_enrollment(
        &remote_control_url,
        remote_control_auth_manager(),
    );

    let response = remote_handle
        .pairing_status(RemoteControlPairingStatusParams {
            pairing_code: Some("pairing-code".to_string()),
            manual_pairing_code: None,
        })
        .await
        .expect("pairing status should refresh after server token auth failure");
    server_task.await.expect("server task should finish");

    assert!(response.claimed);
}

#[tokio::test]
async fn remote_control_pairing_status_maps_user_actionable_backend_errors() {
    for (status, expected_kind) in [
        ("403 Forbidden", io::ErrorKind::PermissionDenied),
        ("404 Not Found", io::ErrorKind::InvalidInput),
        ("410 Gone", io::ErrorKind::InvalidInput),
    ] {
        let (err, _expected_status_url) = pairing_status_error(status, "not available").await;
        assert_eq!(err.kind(), expected_kind);
    }
}

#[tokio::test]
async fn remote_control_pairing_status_preserves_decode_error_context() {
    let (err, expected_status_url) = pairing_status_error("200 OK", "{").await;
    let err = err.to_string();

    assert!(err.contains(&format!(
        "failed to parse remote control pairing status response from `{expected_status_url}`: HTTP 200 OK"
    )));
    assert!(err.contains("request-id: request-123"));
    assert!(err.contains("cf-ray: ray-123"));
    assert!(err.contains("body: {"));
    assert!(err.contains("decode error:"));
}

#[tokio::test]
async fn remote_control_handle_refreshes_after_pairing_auth_failure() {
    let listener = TcpListener::bind("127.0.0.1:0")
        .await
        .expect("listener should bind");
    let remote_control_url = remote_control_url_for_listener(&listener);
    let server_task = tokio::spawn(async move {
        let stale_pairing_request = accept_http_request(&listener).await;
        assert_eq!(
            stale_pairing_request.request_line,
            "POST /backend-api/wham/remote/control/server/pair HTTP/1.1"
        );
        assert_eq!(
            stale_pairing_request.headers.get("authorization"),
            Some(&format!("Bearer {TEST_REMOTE_CONTROL_SERVER_TOKEN}"))
        );
        respond_with_status(stale_pairing_request.stream, "401 Unauthorized", "").await;

        let refresh_request = accept_http_request(&listener).await;
        assert_eq!(
            refresh_request.request_line,
            "POST /backend-api/wham/remote/control/server/refresh HTTP/1.1"
        );
        assert_eq!(
            refresh_request.headers.get("authorization"),
            Some(&"Bearer Access Token".to_string())
        );
        respond_with_json(
            refresh_request.stream,
            remote_control_server_token_response(
                "srv_e_test",
                "env_test",
                TEST_REFRESHED_REMOTE_CONTROL_SERVER_TOKEN,
            ),
        )
        .await;

        let refreshed_pairing_request = accept_http_request(&listener).await;
        assert_eq!(
            refreshed_pairing_request.request_line,
            "POST /backend-api/wham/remote/control/server/pair HTTP/1.1"
        );
        assert_eq!(
            refreshed_pairing_request.headers.get("authorization"),
            Some(&format!(
                "Bearer {TEST_REFRESHED_REMOTE_CONTROL_SERVER_TOKEN}"
            ))
        );
        respond_with_json(
            refreshed_pairing_request.stream,
            json!({
                "pairing_code": "pairing-code",
                "manual_pairing_code": "ABCD-EFGH",
                "server_id": "srv_e_test",
                "environment_id": "env_test",
                "expires_at": "3026-05-22T12:34:56Z",
            }),
        )
        .await;
    });
    let remote_handle = remote_control_handle_with_current_enrollment(
        &remote_control_url,
        remote_control_auth_manager(),
    );

    let response = remote_handle
        .start_pairing(
            RemoteControlPairingStartParams::default(),
            /*app_server_client_name*/ None,
        )
        .await
        .expect("pairing should refresh after server token auth failure");
    server_task.await.expect("server task should finish");

    assert_eq!(
        response,
        RemoteControlPairingStartResponse {
            pairing_code: "pairing-code".to_string(),
            manual_pairing_code: Some("ABCD-EFGH".to_string()),
            environment_id: "env_test".to_string(),
            expires_at: 33_336_362_096,
        }
    );
}

#[tokio::test]
async fn remote_control_handle_recovers_auth_before_refreshing_pairing() {
    let listener = TcpListener::bind("127.0.0.1:0")
        .await
        .expect("listener should bind");
    let remote_control_url = remote_control_url_for_listener(&listener);
    let server_task = tokio::spawn(async move {
        let stale_refresh_request = accept_http_request(&listener).await;
        assert_eq!(
            stale_refresh_request.request_line,
            "POST /backend-api/wham/remote/control/server/refresh HTTP/1.1"
        );
        assert_eq!(
            stale_refresh_request.headers.get("authorization"),
            Some(&"Bearer stale-token".to_string())
        );
        respond_with_status(stale_refresh_request.stream, "401 Unauthorized", "").await;

        let recovered_refresh_request = accept_http_request(&listener).await;
        assert_eq!(
            recovered_refresh_request.request_line,
            "POST /backend-api/wham/remote/control/server/refresh HTTP/1.1"
        );
        assert_eq!(
            recovered_refresh_request.headers.get("authorization"),
            Some(&"Bearer fresh-token".to_string())
        );
        respond_with_json(
            recovered_refresh_request.stream,
            remote_control_server_token_response(
                "srv_e_test",
                "env_test",
                TEST_REFRESHED_REMOTE_CONTROL_SERVER_TOKEN,
            ),
        )
        .await;

        let pairing_request = accept_http_request(&listener).await;
        assert_eq!(
            pairing_request.request_line,
            "POST /backend-api/wham/remote/control/server/pair HTTP/1.1"
        );
        assert_eq!(
            pairing_request.headers.get("authorization"),
            Some(&format!(
                "Bearer {TEST_REFRESHED_REMOTE_CONTROL_SERVER_TOKEN}"
            ))
        );
        respond_with_json(
            pairing_request.stream,
            json!({
                "pairing_code": "pairing-code",
                "manual_pairing_code": "ABCD-EFGH",
                "server_id": "srv_e_test",
                "environment_id": "env_test",
                "expires_at": "3026-05-22T12:34:56Z",
            }),
        )
        .await;
    });
    let codex_home = TempDir::new().expect("temp dir should create");
    let mut stale_auth = remote_control_auth_dot_json(Some("account_id"));
    stale_auth
        .tokens
        .as_mut()
        .expect("stale auth should include tokens")
        .access_token = "stale-token".to_string();
    save_auth(
        codex_home.path(),
        &stale_auth,
        AuthCredentialsStoreMode::File,
        AuthKeyringBackendKind::default(),
    )
    .expect("stale auth should save");
    let auth_manager = AuthManager::shared(
        codex_home.path().to_path_buf(),
        /*enable_codex_api_key_env*/ false,
        AuthCredentialsStoreMode::File,
        /*chatgpt_base_url*/ None,
        AuthKeyringBackendKind::default(),
    )
    .await;
    let mut fresh_auth = remote_control_auth_dot_json(Some("account_id"));
    fresh_auth
        .tokens
        .as_mut()
        .expect("fresh auth should include tokens")
        .access_token = "fresh-token".to_string();
    save_auth(
        codex_home.path(),
        &fresh_auth,
        AuthCredentialsStoreMode::File,
        AuthKeyringBackendKind::default(),
    )
    .expect("fresh auth should save");
    let remote_handle =
        remote_control_handle_with_current_enrollment(&remote_control_url, auth_manager);
    remote_handle
        .current_enrollment
        .lock()
        .await
        .as_mut()
        .expect("current enrollment should exist")
        .expires_at = Some(OffsetDateTime::now_utc() + time::Duration::seconds(29));

    let response = remote_handle
        .start_pairing(
            RemoteControlPairingStartParams::default(),
            /*app_server_client_name*/ None,
        )
        .await
        .expect("pairing should refresh after auth recovery");
    server_task.await.expect("server task should finish");

    assert_eq!(
        response,
        RemoteControlPairingStartResponse {
            pairing_code: "pairing-code".to_string(),
            manual_pairing_code: Some("ABCD-EFGH".to_string()),
            environment_id: "env_test".to_string(),
            expires_at: 33_336_362_096,
        }
    );
}

#[tokio::test]
async fn start_remote_control_pairing_preserves_backend_error_context() {
    let (err, expected_pair_url) =
        pairing_error("503 Service Unavailable", "pairing unavailable").await;

    assert_eq!(
        err,
        format!(
            "remote control pairing failed at `{expected_pair_url}`: HTTP 503 Service Unavailable, request-id: request-123, cf-ray: ray-123, body: pairing unavailable"
        )
    );
}

#[tokio::test]
async fn start_remote_control_pairing_preserves_decode_error_context() {
    let (err, expected_pair_url) = pairing_error("200 OK", "{").await;
    assert!(err.contains(&format!(
        "failed to parse remote control pairing response from `{expected_pair_url}`: HTTP 200 OK"
    )));
    assert!(err.contains("request-id: request-123"));
    assert!(err.contains("cf-ray: ray-123"));
    assert!(err.contains("body: {"));
    assert!(err.contains("decode error:"));
}

#[tokio::test]
async fn start_remote_control_pairing_rejects_mismatched_backend_enrollment() {
    assert_eq!(
        pairing_response_error(json!({
            "pairing_code": "pairing-code",
            "manual_pairing_code": "ABCD-EFGH",
            "server_id": "other-server-id",
            "environment_id": "other-environment-id",
            "expires_at": "3026-05-22T12:34:56Z",
        }))
        .await,
        "remote control pairing returned mismatched enrollment: expected server_id=server-id, environment_id=environment-id; got server_id=other-server-id, environment_id=other-environment-id"
    );
}

#[tokio::test]
async fn start_remote_control_pairing_preserves_expiry_parse_error_context() {
    let err = pairing_response_error(json!({
        "pairing_code": "pairing-code",
        "manual_pairing_code": "ABCD-EFGH",
        "server_id": "server-id",
        "environment_id": "environment-id",
        "expires_at": "not-a-timestamp",
    }))
    .await;

    assert!(err.contains("failed to parse remote control pairing response"));
    assert!(err.contains("HTTP 200 OK"));
    assert!(err.contains("request-id: <none>"));
    assert!(err.contains("cf-ray: <none>"));
    assert!(err.contains("\"expires_at\":\"not-a-timestamp\""));
    assert!(err.contains("expires_at parse error:"));
}

#[tokio::test]
async fn remote_control_handle_disable_keeps_current_enrollment() {
    let remote_handle = remote_control_handle_with_current_enrollment(
        TEST_REMOTE_CONTROL_URL,
        remote_control_auth_manager(),
    );

    remote_handle
        .desired_state_tx
        .send_replace(RemoteControlDesiredState::Disabled);
    assert!(
        remote_handle.current_enrollment.lock().await.is_some(),
        "disabled remote control should keep the selected pairing server"
    );
}

#[tokio::test]
async fn remote_control_handle_reenrolls_after_stale_pairing_enrollment() {
    let listener = TcpListener::bind("127.0.0.1:0")
        .await
        .expect("listener should bind");
    let remote_control_url = remote_control_url_for_listener(&listener);
    let codex_home = TempDir::new().expect("temp dir should create");
    let state_db = remote_control_state_runtime(&codex_home).await;
    let mut remote_handle = remote_control_handle_with_current_enrollment(
        &remote_control_url,
        remote_control_auth_manager_with_home(&codex_home),
    );
    remote_handle.state_db = Some(state_db.clone());
    let stale_enrollment = remote_handle
        .current_enrollment
        .lock()
        .await
        .clone()
        .expect("current enrollment should exist");
    let remote_control_target = stale_enrollment.remote_control_target.clone();
    let refreshed_enrollment = RemoteControlEnrollment {
        remote_control_target: remote_control_target.clone(),
        account_id: "account_id".to_string(),
        environment_id: "env_refreshed".to_string(),
        server_id: "srv_e_refreshed".to_string(),
        server_name: test_server_name(),
        remote_control_token: None,
        expires_at: None,
    };
    update_persisted_remote_control_enrollment(
        Some(state_db.as_ref()),
        &remote_control_target,
        "account_id",
        /*app_server_client_name*/ None,
        Some(&stale_enrollment),
        /*remote_control_enabled*/ Some(true),
    )
    .await
    .expect("stale enrollment should save");
    remote_handle
        .desired_state_tx
        .send_replace(RemoteControlDesiredState::Enabled {
            persistence_preference: Some(true),
        });
    let server_refreshed_enrollment = refreshed_enrollment.clone();
    let server_task = tokio::spawn(async move {
        let stale_pairing_request = accept_http_request(&listener).await;
        assert_eq!(
            stale_pairing_request.request_line,
            "POST /backend-api/wham/remote/control/server/pair HTTP/1.1"
        );
        assert_eq!(
            stale_pairing_request.headers.get("authorization"),
            Some(&format!("Bearer {TEST_REMOTE_CONTROL_SERVER_TOKEN}"))
        );
        respond_with_status(stale_pairing_request.stream, "404 Not Found", "").await;

        let enroll_request = accept_http_request(&listener).await;
        assert_eq!(
            enroll_request.request_line,
            "POST /backend-api/wham/remote/control/server/enroll HTTP/1.1"
        );
        respond_with_json(
            enroll_request.stream,
            remote_control_server_token_response(
                &server_refreshed_enrollment.server_id,
                &server_refreshed_enrollment.environment_id,
                TEST_REFRESHED_REMOTE_CONTROL_SERVER_TOKEN,
            ),
        )
        .await;

        let refreshed_pairing_request = accept_http_request(&listener).await;
        assert_eq!(
            refreshed_pairing_request.request_line,
            "POST /backend-api/wham/remote/control/server/pair HTTP/1.1"
        );
        assert_eq!(
            refreshed_pairing_request.headers.get("authorization"),
            Some(&format!(
                "Bearer {TEST_REFRESHED_REMOTE_CONTROL_SERVER_TOKEN}"
            ))
        );
        respond_with_json(
            refreshed_pairing_request.stream,
            json!({
                "pairing_code": "pairing-code",
                "manual_pairing_code": "ABCD-EFGH",
                "server_id": server_refreshed_enrollment.server_id,
                "environment_id": server_refreshed_enrollment.environment_id,
                "expires_at": "3026-05-22T12:34:56Z",
            }),
        )
        .await;
    });
    let response = remote_handle
        .start_pairing(
            RemoteControlPairingStartParams::default(),
            /*app_server_client_name*/ None,
        )
        .await
        .expect("pairing should re-enroll after stale enrollment");
    server_task.await.expect("server task should finish");

    assert_eq!(
        response,
        RemoteControlPairingStartResponse {
            pairing_code: "pairing-code".to_string(),
            manual_pairing_code: Some("ABCD-EFGH".to_string()),
            environment_id: "env_refreshed".to_string(),
            expires_at: 33_336_362_096,
        }
    );
    assert_eq!(
        state_db
            .get_remote_control_enrollment(
                &remote_control_target.websocket_url,
                "account_id",
                /*app_server_client_name*/ None,
            )
            .await
            .expect("refreshed enrollment should load")
            .expect("refreshed enrollment should exist")
            .remote_control_enabled,
        Some(true)
    );
}

#[tokio::test]
async fn remote_control_handle_discards_pairing_response_after_auth_change() {
    let listener = TcpListener::bind("127.0.0.1:0")
        .await
        .expect("listener should bind");
    let remote_control_url = remote_control_url_for_listener(&listener);
    let codex_home = TempDir::new().expect("temp dir should create");
    save_auth(
        codex_home.path(),
        &remote_control_auth_dot_json(Some("account_id")),
        AuthCredentialsStoreMode::File,
        AuthKeyringBackendKind::default(),
    )
    .expect("initial auth should save");
    let auth_manager = AuthManager::shared(
        codex_home.path().to_path_buf(),
        /*enable_codex_api_key_env*/ false,
        AuthCredentialsStoreMode::File,
        /*chatgpt_base_url*/ None,
        AuthKeyringBackendKind::default(),
    )
    .await;
    let remote_handle =
        remote_control_handle_with_current_enrollment(&remote_control_url, auth_manager.clone());
    let pairing_task = tokio::spawn({
        let remote_handle = remote_handle.clone();
        async move {
            remote_handle
                .start_pairing(
                    RemoteControlPairingStartParams::default(),
                    /*app_server_client_name*/ None,
                )
                .await
        }
    });

    let pairing_request = accept_http_request(&listener).await;
    save_auth(
        codex_home.path(),
        &remote_control_auth_dot_json(Some("next_account_id")),
        AuthCredentialsStoreMode::File,
        AuthKeyringBackendKind::default(),
    )
    .expect("next auth should save");
    auth_manager.reload().await;
    respond_with_json(
        pairing_request.stream,
        json!({
            "pairing_code": "stale-pairing-code",
            "manual_pairing_code": "ABCD-EFGH",
            "server_id": "srv_e_test",
            "environment_id": "env_test",
            "expires_at": "3026-05-22T12:34:56Z",
        }),
    )
    .await;

    assert_eq!(
        pairing_task
            .await
            .expect("pairing task should join")
            .expect_err("stale pairing response should be discarded")
            .to_string(),
        "remote control pairing is unavailable until enrollment completes"
    );
}
