//! Tests for local note reactions (like/announce) with proper authorization.

mod support;

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

/// 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", "correct horse battery staple"),
        ],
    );
    assert_eq!(
        response.status, 303,
        "registering should log in\n{}",
        response.body
    );
}

/// Extract note UUID from profile page HTML.
fn extract_note_uuid(html: &str, author: &str) -> Option<String> {
    // Look for permalink pattern: href="http://.../~author/notes/{uuid}"
    let pattern = format!("/~{author}/notes/");
    let start = html.find(&pattern)?;
    let after_pattern = &html[start + pattern.len()..];
    let end = after_pattern.find('"')?;
    Some(after_pattern[..end].to_string())
}

/// Test: Author cannot like their own note (server-side 403)
#[tokio::test]
async fn author_cannot_like_own_note() -> 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");

    // Post a note
    let response = alice_client.post_form("/~alice/notes", &[("content", "My note")]);
    assert_eq!(response.status, 303);

    // Visit profile to get the note UUID
    let response = alice_client.get("/~alice");
    assert_eq!(response.status, 200);
    let uuid =
        extract_note_uuid(&response.body, "alice").expect("should find note UUID in profile");

    // Try to react to own note - should fail with 403
    let response = alice_client.post_form(&format!("/~alice/notes/{uuid}/react"), &[]);
    assert_eq!(
        response.status, 403,
        "author should not be able to like their own note"
    );

    Ok(())
}

/// Test: Author CAN announce (boost) their own note
#[tokio::test]
async fn author_can_announce_own_note() -> 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");

    // Post a note
    let response = alice_client.post_form("/~alice/notes", &[("content", "My note to boost")]);
    assert_eq!(response.status, 303);

    // Visit profile to get the note UUID
    let response = alice_client.get("/~alice");
    assert_eq!(response.status, 200);
    let uuid =
        extract_note_uuid(&response.body, "alice").expect("should find note UUID in profile");

    // Author should be able to announce their own note
    let response = alice_client.post_form(&format!("/~alice/notes/{uuid}/announce"), &[]);
    assert_eq!(
        response.status, 303,
        "author should be able to announce their own note"
    );

    Ok(())
}

/// Test: User can like a note by another user
#[tokio::test]
async fn user_can_like_other_users_note() -> 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);
    let mut bob_client = Client::new(port);

    register(&mut alice_client, "alice");
    register(&mut bob_client, "bob");

    // Alice posts a note
    let response = alice_client.post_form("/~alice/notes", &[("content", "Alice's note")]);
    assert_eq!(response.status, 303);

    // Visit Alice's profile to get the note UUID
    let response = alice_client.get("/~alice");
    assert_eq!(response.status, 200);
    let uuid =
        extract_note_uuid(&response.body, "alice").expect("should find note UUID in profile");

    // Bob should be able to react to Alice's note
    let response = bob_client.post_form(&format!("/~alice/notes/{uuid}/react"), &[]);
    assert_eq!(
        response.status, 303,
        "non-author should be able to react to a note"
    );

    Ok(())
}
