//! Phase 5 tests: RFC 9421 HTTP Message Signatures

mod support;

use std::time::{Duration, Instant};

use support::ap::RemoteActor;
use support::{Client, Server, free_port};

/// The password the tests register and log in with.
const PASSWORD: &str = "correct horse battery staple";

/// Register a user through the web form.
fn register(client: &mut Client, name: &str) {
    let email = format!("{name}@example.org");
    let response = client.post_form(
        "/register",
        &[("name", name), ("email", &email), ("password", PASSWORD)],
    );
    assert_eq!(
        response.status, 303,
        "registering should log in\n{}",
        response.body
    );
}

/// Test: RemoteActor follows alice using RFC 9421 signature → Accept(Follow) is delivered
#[tokio::test]
async fn rfc9421_follow_is_accepted() -> miette::Result<()> {
    let port = free_port();
    let mut server = Server::spawn_federated(&format!("127.0.0.1:{port}"));
    server.wait_for_connection(port);

    let mut alice_client = Client::new(port);
    register(&mut alice_client, "alice");

    // Start a remote actor recorder
    let recorder_port = free_port();
    let recorder = RemoteActor::serve(recorder_port);

    // Bob follows alice by sending a Follow activity to her inbox
    let follow_json = serde_json::json!({
        "@context": "https://www.w3.org/ns/activitystreams",
        "id": format!("{}/follow/1", recorder.actor_url),
        "type": "Follow",
        "actor": recorder.actor_url,
        "object": format!("http://127.0.0.1:{port}/~alice")
    });
    let body = serde_json::to_string(&follow_json).unwrap();

    let (signature, signature_input, date, content_digest) = support::ap::signed_post_rfc9421(
        &recorder.private_key_pem,
        &recorder.key_id,
        &format!("127.0.0.1:{port}"),
        "/~alice/inbox",
        &body,
    );

    let response = alice_client.post_json_with_headers(
        "/~alice/inbox",
        &body,
        &[
            ("Signature", &signature),
            ("Signature-Input", &signature_input),
            ("Date", &date),
            ("Content-Digest", &content_digest),
            ("Content-Type", "application/activity+json"),
        ],
    );

    assert_eq!(
        response.status, 202,
        "RFC 9421 Follow should be accepted. Server log:"
    );

    // Poll for Accept(Follow) delivery
    let deadline = Instant::now() + Duration::from_secs(10);
    let mut found_accept = false;
    while Instant::now() < deadline {
        std::thread::sleep(Duration::from_millis(50));

        let deliveries = recorder.recorded_deliveries();
        for delivery in &deliveries {
            if let Ok(activity) = serde_json::from_str::<serde_json::Value>(&delivery.body) {
                if activity.get("type").and_then(|t| t.as_str()) == Some("Accept") {
                    if let Some(obj) = activity.get("object") {
                        if obj.get("type").and_then(|t| t.as_str()) == Some("Follow") {
                            found_accept = true;
                            break;
                        }
                    }
                }
            }
        }
        if found_accept {
            break;
        }
    }

    assert!(
        found_accept,
        "alice should send Accept(Follow) for RFC 9421 signed requests. Server log:"
    );

    Ok(())
}
