//! Agent-mode HTTP context construction and gateway registration.

use std::path::Path;
use std::sync::Arc;
use tokio::sync::broadcast;

use crate::agents::AgentPool;
use crate::io::watcher;
use crate::slog;

/// Register this build agent with a gateway using a one-time join token.
///
/// POSTs `{ token, label, address }` to `{gateway_url}/gateway/register`. On
/// success the gateway stores the agent and it will appear in the gateway UI.
pub(super) async fn register_with_gateway(
    gateway_url: &str,
    token: &str,
    label: &str,
    address: &str,
) {
    let client = reqwest::Client::new();
    let url = format!("{}/gateway/register", gateway_url.trim_end_matches('/'));
    let body = serde_json::json!({
        "token": token,
        "label": label,
        "address": address,
    });
    match client.post(&url).json(&body).send().await {
        Ok(resp) if resp.status().is_success() => {
            slog!("[agent-mode] Registered with gateway at {gateway_url}");
        }
        Ok(resp) => {
            slog!(
                "[agent-mode] Gateway registration failed: HTTP {}",
                resp.status()
            );
        }
        Err(e) => {
            slog!("[agent-mode] Gateway registration error: {e}");
        }
    }
}

/// Build a minimal [`AppContext`] for the agent-mode HTTP server.
///
/// The `/crdt-sync` handler receives `Data<&Arc<AppContext>>` but doesn't
/// actually use it (the parameter is named `_ctx`).  We construct a
/// lightweight context with just enough state to satisfy Poem's data
/// extractor.
pub(super) fn build_agent_app_context(
    project_root: &Path,
    port: u16,
    watcher_tx: broadcast::Sender<watcher::WatcherEvent>,
) -> crate::http::context::AppContext {
    let state = crate::state::SessionState::default();
    *state.project_root.lock().unwrap() = Some(project_root.to_path_buf());
    let store_path = project_root.join(".huskies").join("store.json");
    let store = Arc::new(
        crate::store::JsonFileStore::from_path(store_path)
            .unwrap_or_else(|e| panic!("Failed to open store: {e}")),
    );
    let (reconciliation_tx, _) = broadcast::channel(64);
    let (perm_tx, perm_rx) = tokio::sync::mpsc::unbounded_channel();
    let permission_registry = crate::service::permission_router::ResponderRegistry::new();
    crate::service::permission_router::spawn_permission_router(
        perm_rx,
        Arc::clone(&permission_registry),
    );
    let timer_store = Arc::new(crate::service::timer::TimerStore::load(
        project_root.join(".huskies").join("timers.json"),
    ));
    let scheduled_timer_store = Arc::new(crate::service::timer::ScheduledTimerStore::load(
        project_root.join(".huskies").join("scheduled_timers.json"),
    ));
    let agents = Arc::new(AgentPool::new(port, watcher_tx.clone()));
    let services = Arc::new(crate::services::Services {
        project_root: project_root.to_path_buf(),
        agents: Arc::clone(&agents),
        bot_name: "Agent".to_string(),
        bot_user_id: String::new(),
        ambient_rooms: Arc::new(std::sync::Mutex::new(std::collections::HashSet::new())),
        permission_registry,
        pending_perm_replies: crate::service::permission_router::PendingPermReplies::new(),
        permission_timeout_secs: 120,
        status: agents.status_broadcaster(),
        chat_dispatcher: Arc::new(crate::chat::dispatcher::ChatDispatcher::new(1_500)),
    });
    crate::http::context::AppContext {
        state: Arc::new(state),
        store,
        workflow: Arc::new(std::sync::Mutex::new(
            crate::workflow::WorkflowState::default(),
        )),
        services,
        watcher_tx,
        reconciliation_tx,
        perm_tx,
        qa_app_process: Arc::new(std::sync::Mutex::new(None)),
        bot_shutdown: None,
        matrix_shutdown_tx: None,
        timer_store,
        scheduled_timer_store,
        event_trigger_store: Arc::new(
            crate::service::event_triggers::store::EventTriggerStore::load(
                project_root.join(".huskies").join("event_triggers.json"),
            ),
        ),
    }
}
