//! Coverage tests for admin/handlers.rs handler methods.
//!
//! The handler methods are private (generated by #[tool_router]).  We test by
//! calling the workflow functions that every handler delegates to — this
//! exercises the same code paths without requiring visibility hacks.

use crate::tools::workflow;

use super::make_state;

// ── Engagement handlers ───────────────────────────────────────────────

#[tokio::test]
async fn admin_quote_tweet() {
    let state = make_state().await;
    let result = workflow::x_actions::quote_tweet(&state, "quoting this", "123", None).await;
    // NullX returns AuthExpired — handler returns the error text, not a hard error
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_like_tweet() {
    let state = make_state().await;
    let result = workflow::x_actions::like_tweet(&state, "123").await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_follow_user() {
    let state = make_state().await;
    let result = workflow::x_actions::follow_user(&state, "u2").await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_unfollow_user() {
    let state = make_state().await;
    let result = workflow::x_actions::unfollow_user(&state, "u2").await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_retweet() {
    let state = make_state().await;
    let result = workflow::x_actions::retweet(&state, "123").await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_unretweet() {
    let state = make_state().await;
    let result = workflow::x_actions::unretweet(&state, "123").await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_delete_tweet() {
    let state = make_state().await;
    let result = workflow::x_actions::delete_tweet(&state, "123").await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_unlike_tweet() {
    let state = make_state().await;
    let result = workflow::x_actions::unlike_tweet(&state, "123").await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_bookmark_tweet() {
    let state = make_state().await;
    let result = workflow::x_actions::bookmark_tweet(&state, "123").await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_unbookmark_tweet() {
    let state = make_state().await;
    let result = workflow::x_actions::unbookmark_tweet(&state, "123").await;
    assert!(!result.is_empty());
}

// ── Write handlers ────────────────────────────────────────────────────

#[tokio::test]
async fn admin_post_thread() {
    let state = make_state().await;
    let tweets = vec!["tweet 1".to_string(), "tweet 2".to_string()];
    let result = workflow::x_actions::post_thread(&state, &tweets, None).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_post_tweet_dry_run() {
    let state = make_state().await;
    let result = workflow::x_actions::post_tweet_dry_run(&state, "dry run tweet", None).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_post_thread_dry_run() {
    let state = make_state().await;
    let tweets = vec!["part 1".to_string()];
    let result = workflow::x_actions::post_thread_dry_run(&state, &tweets, None).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_upload_media_dry_run() {
    let state = make_state().await;
    // dry_run=true avoids actual file I/O
    let result =
        workflow::x_actions::upload_media(&state, "/tmp/nonexistent.jpg", None, true).await;
    assert!(!result.is_empty());
}

// ── Read handlers ─────────────────────────────────────────────────────

#[tokio::test]
async fn admin_get_home_timeline() {
    let state = make_state().await;
    let result = workflow::x_actions::get_home_timeline(&state, 20, None).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_get_followers() {
    let state = make_state().await;
    let result = workflow::x_actions::get_followers(&state, "u1", 100, None).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_get_following() {
    let state = make_state().await;
    let result = workflow::x_actions::get_following(&state, "u1", 100, None).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_get_user_by_id() {
    let state = make_state().await;
    let result = workflow::x_actions::get_user_by_id(&state, "u1").await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_get_liked_tweets() {
    let state = make_state().await;
    let result = workflow::x_actions::get_liked_tweets(&state, "u1", 10, None).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_get_bookmarks() {
    let state = make_state().await;
    let result = workflow::x_actions::get_bookmarks(&state, 10, None).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_get_users_by_ids() {
    let state = make_state().await;
    let result = workflow::x_actions::get_users_by_ids(&state, &["u1"]).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_get_tweet_liking_users() {
    let state = make_state().await;
    let result = workflow::x_actions::get_tweet_liking_users(&state, "123", 100, None).await;
    assert!(!result.is_empty());
}

// ── Universal request handlers ────────────────────────────────────────

#[tokio::test]
async fn admin_x_get() {
    let state = make_state().await;
    let result =
        workflow::x_actions::x_request::x_get(&state, "/2/tweets", None, None, None, false, None)
            .await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_x_post() {
    let state = make_state().await;
    let result = workflow::x_actions::x_request::x_post_audited(
        &state,
        "/2/tweets",
        None,
        None,
        Some(r#"{"text":"test"}"#),
        None,
    )
    .await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_x_put() {
    let state = make_state().await;
    let result = workflow::x_actions::x_request::x_put_audited(
        &state,
        "/2/tweets/123/hidden",
        None,
        None,
        Some(r#"{"hidden":true}"#),
        None,
    )
    .await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_x_delete() {
    let state = make_state().await;
    let result =
        workflow::x_actions::x_request::x_delete_audited(&state, "/2/tweets/123", None, None, None)
            .await;
    assert!(!result.is_empty());
}

// ── Context / analytics handlers ──────────────────────────────────────

#[tokio::test]
async fn admin_get_author_context() {
    let state = make_state().await;
    let result = workflow::context::get_author_context(&state, "123").await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_recommend_engagement_action() {
    let state = make_state().await;
    let result =
        workflow::context::recommend_engagement(&state, "tuitbot", "Check this out!", None).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_topic_performance_snapshot() {
    let state = make_state().await;
    let result = workflow::context::topic_performance_snapshot(&state.pool, 30).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_get_x_usage() {
    let state = make_state().await;
    let result = workflow::actions::get_action_counts(&state.pool, 7, &state.config).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_get_mcp_tool_metrics() {
    let state = make_state().await;
    let result = workflow::telemetry::get_mcp_tool_metrics(&state.pool, 24).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_get_mcp_error_breakdown() {
    let state = make_state().await;
    let result = workflow::telemetry::get_mcp_error_breakdown(&state.pool, 24).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_find_reply_opportunities() {
    let state = make_state().await;
    let result =
        workflow::discovery::list_unreplied_tweets_with_limit(&state.pool, 0.0, 20, &state.config)
            .await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_draft_replies_for_candidates() {
    let state = make_state().await;
    // No LLM configured — the composite will return an llm_not_configured response
    let result = workflow::composite::draft_replies::execute(&state, &[], None, false).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_propose_and_queue_replies() {
    let state = make_state().await;
    let result = workflow::composite::propose_queue::execute(&state, &[], false).await;
    assert!(!result.is_empty());
}

#[tokio::test]
async fn admin_generate_thread_plan() {
    let state = make_state().await;
    // No LLM configured — composite returns llm_not_configured response text, not panic
    let result =
        workflow::composite::thread_plan::execute(&state, "Rust async", None, None, None).await;
    assert!(!result.is_empty());
}
