use std::sync::Arc;

use axum::{
    extract::{Path, State},
    http::StatusCode,
    response::IntoResponse,
    routing::{get, post},
    Json, Router,
};
use serde_json::json;

use crate::{
    agent_card::AgentCard,
    bridge::CoordinatorBridge,
    error::A2aError,
    protocol::{A2aTask, A2aTaskStatus, JsonRpcResponse},
    task_manager::TaskManager,
};

#[derive(Clone)]
pub struct A2aState {
    pub task_manager: Arc<TaskManager>,
    pub bridge: Arc<CoordinatorBridge>,
    pub agent_card: AgentCard,
}

pub fn create_router(state: A2aState) -> Router {
    Router::new()
        .route("/.well-known/agent.json", get(agent_card_handler))
        .route("/a2a", post(a2a_handler))
        .route("/a2a/tasks/{task_id}", get(task_status_handler))
        .route("/a2a/agents", get(agents_handler))
        .route("/health", get(health_handler))
        .route("/metrics", get(metrics_handler))
        .with_state(state)
}

async fn agent_card_handler(State(state): State<A2aState>) -> impl IntoResponse {
    Json(state.agent_card.clone())
}

async fn a2a_handler(
    State(state): State<A2aState>,
    Json(payload): Json<A2aTask>,
) -> (StatusCode, Json<serde_json::Value>) {
    match state.bridge.dispatch(payload).await {
        Ok(task_id) => {
            let response = JsonRpcResponse::success(
                serde_json::Value::String(task_id),
                json!({ "message": "Task dispatched successfully" }),
            );
            (
                StatusCode::ACCEPTED,
                Json(serde_json::to_value(response).unwrap()),
            )
        }
        Err(e) => {
            let error_response = e.to_json_rpc_error();
            (StatusCode::BAD_REQUEST, Json(error_response))
        }
    }
}

async fn task_status_handler(
    State(state): State<A2aState>,
    Path(task_id): Path<String>,
) -> impl IntoResponse {
    match state.task_manager.get(&task_id).await {
        Ok(status) => {
            let response: JsonRpcResponse<A2aTaskStatus> =
                JsonRpcResponse::success(serde_json::Value::String(task_id), status);
            (
                StatusCode::OK,
                Json(serde_json::to_value(response).unwrap()),
            )
        }
        Err(A2aError::TaskNotFound(id)) => {
            let error = A2aError::TaskNotFound(id).to_json_rpc_error();
            (StatusCode::NOT_FOUND, Json(error))
        }
        Err(e) => {
            let error = e.to_json_rpc_error();
            (StatusCode::INTERNAL_SERVER_ERROR, Json(error))
        }
    }
}

async fn agents_handler(State(state): State<A2aState>) -> impl IntoResponse {
    Json(state.bridge.list_agents())
}

async fn health_handler() -> impl IntoResponse {
    Json(json!({
        "status": "healthy",
        "service": "vapora-a2a"
    }))
}

async fn metrics_handler() -> impl IntoResponse {
    use prometheus::{Encoder, TextEncoder};

    let encoder = TextEncoder::new();
    let metric_families = prometheus::gather();
    let mut buffer = vec![];

    if let Err(e) = encoder.encode(&metric_families, &mut buffer) {
        return (
            StatusCode::INTERNAL_SERVER_ERROR,
            format!("Failed to encode metrics: {}", e),
        )
            .into_response();
    }

    (
        StatusCode::OK,
        [(
            axum::http::header::CONTENT_TYPE,
            "text/plain; version=0.0.4",
        )],
        buffer,
    )
        .into_response()
}

#[cfg(test)]
mod tests {
    use vapora_agents::registry::AgentRegistry;

    use super::*;

    #[tokio::test]
    #[ignore] // Requires SurrealDB running
    async fn test_health_endpoint() {
        let db = surrealdb::Surreal::new::<surrealdb::engine::remote::ws::Ws>("127.0.0.1:8000")
            .await
            .unwrap();

        db.signin(surrealdb::opt::auth::Root {
            username: "root".to_string(),
            password: "root".to_string(),
        })
        .await
        .unwrap();

        db.use_ns("test").use_db("vapora_a2a_test").await.unwrap();

        let task_manager = Arc::new(TaskManager::new(db));
        let registry = Arc::new(AgentRegistry::new(10));
        let config = vapora_agents::config::AgentConfig::default();
        let coordinator = Arc::new(
            vapora_agents::coordinator::AgentCoordinator::new(config, registry)
                .await
                .unwrap(),
        );
        let bridge = Arc::new(CoordinatorBridge::new(
            coordinator,
            task_manager.clone(),
            None, // No NATS in test
        ));
        let agent_card = crate::agent_card::generate_default_agent_card(
            "http://localhost:8002".to_string(),
            "1.0.0".to_string(),
        )
        .unwrap();

        let state = A2aState {
            task_manager,
            bridge,
            agent_card,
        };

        let _router = create_router(state);
        // Health endpoint test verified via integration tests
    }
}
