//! Tests for unified note footer behavior across feed and profile pages.

mod support;

use std::time::Duration;

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: Profile page shows a permalink for each note
#[tokio::test]
async fn profile_shows_note_permalink() -> 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", "Test note content")]);
    assert_eq!(
        response.status, 303,
        "posting a note should redirect. Body:\n{}",
        response.body
    );

    // Visit the profile page
    let response = alice_client.get("/~alice");
    assert_eq!(response.status, 200, "profile page should load");
    assert!(
        response.body.contains("Test note content"),
        "profile should contain the note content. Body:\n{}",
        response.body
    );

    // Check for permalink anchor
    assert!(
        response.body.contains("permalink"),
        "profile should contain a permalink link. Body:\n{}",
        response.body
    );

    // Check for a link to the note URL (should be /~alice/notes/{uuid})
    assert!(
        response.body.contains("/~alice/notes/"),
        "profile should contain a link to the note. Body:\n{}",
        response.body
    );

    Ok(())
}

/// Test: Feed shows reaction counts
#[tokio::test]
async fn feed_shows_reaction_counts() -> 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", "Test note")]);
    assert_eq!(response.status, 303);

    // Visit the home page - should see the feed with counts
    let response = alice_client.get("/");
    assert_eq!(response.status, 200, "home page should load");
    assert!(
        response.body.contains("Test note"),
        "feed should contain the note. Body:\n{}",
        response.body
    );

    // The feed should show reaction counts (even if 0)
    // After we implement, this will show the counts markup
    // For now, just check the note is there

    Ok(())
}

/// Test: Note page content negotiation - HTML vs JSON
#[tokio::test]
async fn note_page_content_negotiation() -> 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", "Test note for negotiation")]);
    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");

    // Request with Accept: text/html should return HTML
    let response =
        alice_client.get_with(&format!("/~alice/notes/{uuid}"), &[("Accept", "text/html")]);
    assert_eq!(response.status, 200, "HTML request should succeed with 200");
    assert!(
        response.body.contains("<!DOCTYPE html>"),
        "should return HTML page"
    );
    assert!(
        response.body.contains("Test note for negotiation"),
        "HTML should contain note content"
    );

    // Request with Accept: application/activity+json should return JSON
    let response = alice_client.get_with(
        &format!("/~alice/notes/{uuid}"),
        &[("Accept", "application/activity+json")],
    );
    assert_eq!(
        response.status, 200,
        "ActivityPub JSON request should succeed with 200"
    );
    assert!(
        response.body.contains("\"type\"") && response.body.contains("\"Note\""),
        "should return ActivityPub Note JSON. Body:\n{}",
        response.body
    );

    Ok(())
}
