//! Per-turn MCP OAuth token resolution.
//!
//! Hadrian never persists MCP bearers, so they must be re-resolved every turn
//! and folded into `McpServerSettings.resolved_authorization` (which
//! `build_tools` reads each request). OAuth discovery + the loopback callback
//! all live in `hagent-core`; this module only bridges the interactive step to
//! ACP by surfacing the authorization URL to the user.

use agent_client_protocol as acp;
use agent_client_protocol::ConnectionTo;
use agent_client_protocol::schema::{
    ContentBlock, ContentChunk, SessionId, SessionNotification, SessionUpdate, TextContent,
};
use hagent_core::TokenStore;
use hagent_core::mcp::{self, McpServerSettings};

/// Resolve/refresh OAuth bearers for any servers that need them. For servers
/// requiring interactive login, surface the authorization URL (and best-effort
/// open the browser), block on the loopback callback, then re-resolve so the
/// fresh bearer lands in `resolved_authorization`. No-op when no server uses
/// OAuth.
pub async fn ensure_mcp_auth(
    servers: &mut [McpServerSettings],
    store: &TokenStore,
    cx: &ConnectionTo<acp::Client>,
    session_id: &SessionId,
) {
    if !servers.iter().any(McpServerSettings::needs_oauth) {
        return;
    }
    let outcome = mcp::ensure_tokens(servers, store).await;
    if outcome.needs_login.is_empty() {
        return;
    }

    for label in outcome.needs_login {
        let Some(server) = servers.iter().find(|s| s.server_label == label).cloned() else {
            continue;
        };
        notify(
            cx,
            session_id,
            &format!("MCP server '{label}' needs authorization — opening your browser…"),
        );
        let cx2 = cx.clone();
        let sid = session_id.clone();
        let lbl = label.clone();
        let open_browser = move |url: &str| {
            notify(&cx2, &sid, &format!("Authorize '{lbl}': {url}"));
            let _ = open::that(url);
        };
        if let Err(e) = mcp::login(&server, store, open_browser).await {
            notify(
                cx,
                session_id,
                &format!("MCP login for '{label}' failed: {e}"),
            );
        }
    }

    // Fold freshly-minted bearers into `resolved_authorization`.
    let _ = mcp::ensure_tokens(servers, store).await;
}

fn notify(cx: &ConnectionTo<acp::Client>, session_id: &SessionId, msg: &str) {
    let update = SessionUpdate::AgentMessageChunk(ContentChunk::new(ContentBlock::Text(
        TextContent::new(format!("\n{msg}")),
    )));
    let _ = cx.send_notification(SessionNotification::new(session_id.clone(), update));
}
