//! HTTP API server

use axum::{
    extract::State,
    http::StatusCode,
    routing::{get, post},
    Json, Router,
};
use serde::{Deserialize, Serialize};
use tower_http::{
    cors::{Any, CorsLayer},
    trace::TraceLayer,
};
use tracing::info;

use crate::{
    agent::{AgentConfig, AgentManager},
    config::Config,
    tools::ToolRegistry,
    vector_store::{simple_embed, Document, VectorStore},
};

/// Application state
#[derive(Clone)]
pub struct AppState {
    pub config: Config,
    pub vector_store: VectorStore,
    pub tool_registry: ToolRegistry,
    pub agent_manager: AgentManager,
}

/// Create the Axum router
pub fn create_app(config: Config, vector_store: VectorStore, tool_registry: ToolRegistry) -> Router {
    let agent_manager = AgentManager::new(tool_registry.clone());
    
    let state = AppState {
        config,
        vector_store,
        tool_registry,
        agent_manager,
    };
    
    Router::new()
        // Health check
        .route("/health", get(health_check))
        
        // Agent endpoints
        .route("/api/agents", post(create_agent))
        .route("/api/agents", get(list_agents))
        .route("/api/agents/:id/prompt", post(execute_prompt))
        .route("/api/agents/:id", get(get_agent))
        .route("/api/agents/:id", delete(delete_agent))
        
        // Council endpoints
        .route("/api/councils", post(create_council))
        .route("/api/councils", get(list_councils))
        .route("/api/councils/:id/execute", post(execute_council))
        
        // Tool endpoints
        .route("/api/tools", get(list_tools))
        .route("/api/tools/search", post(search_tools))
        
        // Vector store endpoints
        .route("/api/documents", post(add_document))
        .route("/api/documents", get(list_documents))
        .route("/api/documents/search", post(search_documents))
        .route("/api/documents/:id", get(get_document))
        .route("/api/documents/:id", delete(delete_document))
        
        // State
        .with_state(state)
        // Middleware
        .layer(TraceLayer::new_for_http())
        .layer(
            CorsLayer::new()
                .allow_origin(Any)
                .allow_methods(Any)
                .allow_headers(Any),
        )
}

// Health check handler
async fn health_check() -> Json<serde_json::Value> {
    Json(serde_json::json!({
        "status": "ok",
        "service": "qwenclaw-rig"
    }))
}

// ============ Agent Endpoints ============

#[derive(Debug, Deserialize)]
struct CreateAgentRequest {
    name: String,
    preamble: String,
    model: Option<String>,
    provider: Option<String>,
    temperature: Option<f32>,
}

#[derive(Debug, Serialize)]
struct CreateAgentResponse {
    session_id: String,
}

async fn create_agent(
    State(state): State<AppState>,
    Json(payload): Json<CreateAgentRequest>,
) -> Result<Json<CreateAgentResponse>, StatusCode> {
    let config = AgentConfig {
        name: payload.name,
        preamble: payload.preamble,
        model: payload.model.unwrap_or(state.config.default_model.clone()),
        provider: payload.provider.unwrap_or(state.config.default_provider.clone()),
        temperature: payload.temperature.unwrap_or(0.7),
        max_turns: 5,
    };
    
    let session_id = state.agent_manager
        .create_session(config)
        .await
        .map_err(|e| {
            tracing::error!("Failed to create agent: {}", e);
            StatusCode::INTERNAL_SERVER_ERROR
        })?;
    
    Ok(Json(CreateAgentResponse { session_id }))
}

async fn list_agents(
    State(state): State<AppState>,
) -> Json<serde_json::Value> {
    let sessions = state.agent_manager.list_sessions().await;
    
    Json(serde_json::json!({
        "agents": sessions.iter().map(|s| serde_json::json!({
            "id": s.id,
            "name": s.config.name,
            "model": s.config.model,
            "provider": s.config.provider,
        })).collect::<Vec<_>>()
    }))
}

#[derive(Debug, Deserialize)]
struct PromptRequest {
    prompt: String,
}

async fn execute_prompt(
    State(state): State<AppState>,
    axum::extract::Path(id): axum::extract::Path<String>,
    Json(payload): Json<PromptRequest>,
) -> Result<Json<serde_json::Value>, StatusCode> {
    let response = state.agent_manager
        .execute_prompt(&id, &payload.prompt)
        .await
        .map_err(|e| {
            tracing::error!("Failed to execute prompt: {}", e);
            StatusCode::INTERNAL_SERVER_ERROR
        })?;
    
    Ok(Json(serde_json::json!({
        "response": response
    })))
}

async fn get_agent(
    State(state): State<AppState>,
    axum::extract::Path(id): axum::extract::Path<String>,
) -> Result<Json<serde_json::Value>, StatusCode> {
    let session = state.agent_manager
        .get_session(&id)
        .await
        .ok_or(StatusCode::NOT_FOUND)?;
    
    Ok(Json(serde_json::json!({
        "agent": {
            "id": session.id,
            "name": session.config.name,
            "preamble": session.config.preamble,
            "model": session.config.model,
            "provider": session.config.provider,
            "temperature": session.config.temperature,
        }
    })))
}

async fn delete_agent(
    State(state): State<AppState>,
    axum::extract::Path(id): axum::extract::Path<String>,
) -> Result<StatusCode, StatusCode> {
    state.agent_manager
        .delete_session(&id)
        .await
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    
    Ok(StatusCode::NO_CONTENT)
}

// ============ Council Endpoints ============

#[derive(Debug, Deserialize)]
struct CreateCouncilRequest {
    name: String,
    agents: Vec<CreateAgentRequest>,
}

async fn create_council(
    State(state): State<AppState>,
    Json(payload): Json<CreateCouncilRequest>,
) -> Result<Json<serde_json::Value>, StatusCode> {
    let agent_configs: Vec<AgentConfig> = payload.agents
        .into_iter()
        .map(|a| AgentConfig {
            name: a.name,
            preamble: a.preamble,
            model: a.model.unwrap_or_else(|| state.config.default_model.clone()),
            provider: a.provider.unwrap_or_else(|| state.config.default_provider.clone()),
            temperature: a.temperature.unwrap_or(0.7),
            max_turns: 5,
        })
        .collect();
    
    let council_id = state.agent_manager
        .create_council(&payload.name, agent_configs)
        .await
        .map_err(|e| {
            tracing::error!("Failed to create council: {}", e);
            StatusCode::INTERNAL_SERVER_ERROR
        })?;
    
    Ok(Json(serde_json::json!({
        "council_id": council_id
    })))
}

async fn list_councils(
    State(state): State<AppState>,
) -> Json<serde_json::Value> {
    let councils = state.agent_manager.list_councils().await;
    
    Json(serde_json::json!({
        "councils": councils.iter().map(|c| serde_json::json!({
            "id": c.id,
            "name": c.name,
            "agents": c.agents.iter().map(|a| serde_json::json!({
                "id": a.id,
                "name": a.config.name,
            })).collect::<Vec<_>>()
        })).collect::<Vec<_>>()
    }))
}

#[derive(Debug, Deserialize)]
struct ExecuteCouncilRequest {
    task: String,
}

async fn execute_council(
    State(state): State<AppState>,
    axum::extract::Path(id): axum::extract::Path<String>,
    Json(payload): Json<ExecuteCouncilRequest>,
) -> Result<Json<serde_json::Value>, StatusCode> {
    let response = state.agent_manager
        .execute_council(&id, &payload.task)
        .await
        .map_err(|e| {
            tracing::error!("Failed to execute council: {}", e);
            StatusCode::INTERNAL_SERVER_ERROR
        })?;
    
    Ok(Json(serde_json::json!({
        "response": response
    })))
}

// ============ Tool Endpoints ============

async fn list_tools(
    State(state): State<AppState>,
) -> Json<serde_json::Value> {
    let tools = state.tool_registry.get_all_tools().await;
    
    Json(serde_json::json!({
        "tools": tools
    }))
}

#[derive(Debug, Deserialize)]
struct SearchToolsRequest {
    query: String,
    limit: Option<usize>,
}

async fn search_tools(
    State(state): State<AppState>,
    Json(payload): Json<SearchToolsRequest>,
) -> Json<serde_json::Value> {
    let limit = payload.limit.unwrap_or(10);
    let tools = state.tool_registry.search_tools(&payload.query, limit).await;
    
    Json(serde_json::json!({
        "tools": tools
    }))
}

// ============ Document Endpoints ============

#[derive(Debug, Deserialize)]
struct AddDocumentRequest {
    content: String,
    metadata: Option<serde_json::Value>,
}

async fn add_document(
    State(state): State<AppState>,
    Json(payload): Json<AddDocumentRequest>,
) -> Result<Json<serde_json::Value>, StatusCode> {
    let doc = Document {
        id: uuid::Uuid::new_v4().to_string(),
        content: payload.content.clone(),
        metadata: payload.metadata.unwrap_or_default(),
        embedding: simple_embed(&payload.content),
    };
    
    state.vector_store
        .add_document(&doc)
        .map_err(|e| {
            tracing::error!("Failed to add document: {}", e);
            StatusCode::INTERNAL_SERVER_ERROR
        })?;
    
    Ok(Json(serde_json::json!({
        "id": doc.id
    })))
}

async fn list_documents(
    State(state): State<AppState>,
) -> Result<Json<serde_json::Value>, StatusCode> {
    let count = state.vector_store.count()
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    
    Ok(Json(serde_json::json!({
        "count": count
    })))
}

#[derive(Debug, Deserialize)]
struct SearchDocumentsRequest {
    query: String,
    limit: Option<usize>,
}

async fn search_documents(
    State(state): State<AppState>,
    Json(payload): Json<SearchDocumentsRequest>,
) -> Result<Json<serde_json::Value>, StatusCode> {
    let limit = payload.limit.unwrap_or(10);
    let query_embedding = simple_embed(&payload.query);
    
    let docs = state.vector_store
        .search(&query_embedding, limit)
        .map_err(|e| {
            tracing::error!("Failed to search documents: {}", e);
            StatusCode::INTERNAL_SERVER_ERROR
        })?;
    
    Ok(Json(serde_json::json!({
        "documents": docs.iter().map(|d| serde_json::json!({
            "id": d.id,
            "content": d.content,
            "metadata": d.metadata,
        })).collect::<Vec<_>>()
    })))
}

async fn get_document(
    State(state): State<AppState>,
    axum::extract::Path(id): axum::extract::Path<String>,
) -> Result<Json<serde_json::Value>, StatusCode> {
    let doc = state.vector_store
        .get_document(&id)
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
        .ok_or(StatusCode::NOT_FOUND)?;
    
    Ok(Json(serde_json::json!({
        "document": {
            "id": doc.id,
            "content": doc.content,
            "metadata": doc.metadata,
        }
    })))
}

async fn delete_document(
    State(state): State<AppState>,
    axum::extract::Path(id): axum::extract::Path<String>,
) -> Result<StatusCode, StatusCode> {
    state.vector_store
        .delete_document(&id)
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    
    Ok(StatusCode::NO_CONTENT)
}
