// SPDX-FileCopyrightText: 2026 Ololduck <ololduck@vit.am> and contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later

//! Phase 1 tests: instance actor and migrations

mod support;

use support::{Server, free_port};

/// Test: Instance actor endpoint returns Application actor
#[tokio::test]
async fn instance_actor_serves_application_actor() -> 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 client = support::Client::new(port);

    // Request with ActivityPub content negotiation
    let response = client.get_ap("/actor")?;

    // Should be Application actor
    assert_eq!(
        response.get("type").and_then(|v| v.as_str()),
        Some("Application"),
        "should be Application type, got: {:?}",
        response
    );

    // Should have inbox
    assert!(
        response.get("inbox").is_some(),
        "should have inbox, got: {:?}",
        response
    );

    // Should have publicKey
    assert!(
        response.get("publicKey").is_some(),
        "should have publicKey, got: {:?}",
        response
    );

    Ok(())
}

/// Test: Instance actor returns 404 for browser requests
#[tokio::test]
async fn instance_actor_rejects_browser_requests() -> 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 client = support::Client::new(port);

    // Request with browser Accept header (no AP content negotiation)
    let response = client.get("/actor");

    assert_eq!(response.status, 404, "browser requests should be rejected");

    Ok(())
}

/// Test: Instance actor is singleton (same ID on repeated requests)
#[tokio::test]
async fn instance_actor_is_singleton() -> 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 client = support::Client::new(port);

    let response1 = client.get_ap("/actor")?;
    let response2 = client.get_ap("/actor")?;

    // Extract id from both responses
    let id1 = response1.get("id").and_then(|v| v.as_str());
    let id2 = response2.get("id").and_then(|v| v.as_str());

    assert!(
        id1.is_some() && id2.is_some(),
        "both responses should have id"
    );

    assert_eq!(
        id1, id2,
        "instance actor should be singleton (same id), got: {:?} and {:?}",
        id1, id2
    );

    Ok(())
}

/// Test: Instance actor inbox rejects unsigned requests with 401
#[tokio::test]
async fn instance_actor_inbox_rejects_unsigned_requests() -> 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 client = support::Client::new(port);

    // POST a simple activity to the inbox (unsigned)
    let response = client.post_form("/actor/inbox", &[("test", "data")]);

    // Should return 401 Unauthorized for unsigned requests
    assert_eq!(
        response.status, 401,
        "expected 401, got: {}",
        response.status
    );

    Ok(())
}
