use actix_web::{HttpResponse, web, web::ServiceConfig};
use service::AppService;
use service::agent::session::{
    AgentSessionResponse, CreateAgentSession, UpdateAgentSession,
};
use session::Session;
use uuid::Uuid;

use crate::error::{ApiError, ok_json};

pub fn configure(cfg: &mut ServiceConfig) {
    cfg.service(
        web::resource("/sessions")
            .route(web::get().to(list_sessions))
            .route(web::post().to(create_session)),
    )
    .service(
        web::resource("/sessions/search").route(web::get().to(search_sessions)),
    )
    .service(
        web::resource("/sessions/{id}")
            .route(web::get().to(get_session))
            .route(web::patch().to(update_session))
            .route(web::delete().to(delete_session)),
    )
    .service(
        web::resource("/sessions/{id}/toolsets")
            .route(web::patch().to(update_session_toolsets)),
    );
}
#[utoipa::path(
    get, path = "/api/v1/agent/sessions",
    responses((status = 200, body = Vec<AgentSessionResponse>)),
    security(("session" = []))
)]
pub async fn list_sessions(
    session: Session,
    service: web::Data<AppService>,
) -> Result<HttpResponse, ApiError> {
    let user_id = session
        .user()
        .ok_or(ApiError(service::error::AppError::Unauthorized))?;
    ok_json(service.agent_session_list(user_id).await?)
}
#[utoipa::path(
    post, path = "/api/v1/agent/sessions",
    request_body = CreateAgentSession,
    responses((status = 200, body = AgentSessionResponse)),
    security(("session" = []))
)]
pub async fn create_session(
    session: Session,
    service: web::Data<AppService>,
    body: web::Json<CreateAgentSession>,
) -> Result<HttpResponse, ApiError> {
    let user_id = session
        .user()
        .ok_or(ApiError(service::error::AppError::Unauthorized))?;
    ok_json(
        service
            .agent_session_create(user_id, body.into_inner())
            .await?,
    )
}
#[utoipa::path(
    get, path = "/api/v1/agent/sessions/{id}",
    params(("id" = Uuid, Path)),
    responses((status = 200, body = AgentSessionResponse)),
    security(("session" = []))
)]
pub async fn get_session(
    session: Session,
    service: web::Data<AppService>,
    path: web::Path<Uuid>,
) -> Result<HttpResponse, ApiError> {
    let user_id = session
        .user()
        .ok_or(ApiError(service::error::AppError::Unauthorized))?;
    ok_json(
        service
            .agent_session_get(user_id, path.into_inner())
            .await?,
    )
}
#[utoipa::path(
    patch, path = "/api/v1/agent/sessions/{id}",
    params(("id" = Uuid, Path)),
    request_body = UpdateAgentSession,
    responses((status = 200, body = AgentSessionResponse)),
    security(("session" = []))
)]
pub async fn update_session(
    session: Session,
    service: web::Data<AppService>,
    path: web::Path<Uuid>,
    body: web::Json<UpdateAgentSession>,
) -> Result<HttpResponse, ApiError> {
    let user_id = session
        .user()
        .ok_or(ApiError(service::error::AppError::Unauthorized))?;
    ok_json(
        service
            .agent_session_update(user_id, path.into_inner(), body.into_inner())
            .await?,
    )
}
#[utoipa::path(
    delete, path = "/api/v1/agent/sessions/{id}",
    params(("id" = Uuid, Path)),
    responses((status = 200)),
    security(("session" = []))
)]
pub async fn delete_session(
    session: Session,
    service: web::Data<AppService>,
    path: web::Path<Uuid>,
) -> Result<HttpResponse, ApiError> {
    let user_id = session
        .user()
        .ok_or(ApiError(service::error::AppError::Unauthorized))?;
    service
        .agent_session_delete(user_id, path.into_inner())
        .await?;
    Ok(HttpResponse::Ok().json(serde_json::json!({ "deleted": true })))
}

#[derive(Debug, serde::Deserialize, utoipa::IntoParams)]
pub struct SearchQuery {
    pub q: String,
    #[serde(default = "default_limit")]
    pub limit: u32,
}

const fn default_limit() -> u32 {
    20
}
#[utoipa::path(
    get, path = "/api/v1/agent/sessions/search",
    params(("q" = String, Query), ("limit" = Option<u32>, Query)),
    responses((status = 200, body = Vec<AgentSessionResponse>)),
    security(("session" = []))
)]
pub async fn search_sessions(
    session: Session,
    service: web::Data<AppService>,
    query: web::Query<SearchQuery>,
) -> Result<HttpResponse, ApiError> {
    let user_id = session
        .user()
        .ok_or(ApiError(service::error::AppError::Unauthorized))?;
    ok_json(
        service
            .agent_session_search(user_id, &query.q, query.limit)
            .await?,
    )
}

#[derive(Debug, serde::Deserialize, utoipa::ToSchema)]
pub struct UpdateToolsetsRequest {
    pub enabled: Option<Vec<String>>,
    pub disabled: Option<Vec<String>>,
}
#[utoipa::path(
    patch, path = "/api/v1/agent/sessions/{id}/toolsets",
    params(("id" = Uuid, Path)),
    request_body = UpdateToolsetsRequest,
    responses((status = 200, body = AgentSessionResponse)),
    security(("session" = []))
)]
pub async fn update_session_toolsets(
    session: Session,
    service: web::Data<AppService>,
    path: web::Path<Uuid>,
    body: web::Json<UpdateToolsetsRequest>,
) -> Result<HttpResponse, ApiError> {
    let user_id = session
        .user()
        .ok_or(ApiError(service::error::AppError::Unauthorized))?;
    ok_json(
        service
            .agent_session_update_toolsets(
                user_id,
                path.into_inner(),
                body.enabled.clone(),
                body.disabled.clone(),
            )
            .await?,
    )
}
