use axum::{
    Json,
    extract::{Path, Query, State},
};
use serde_json::{Value, json};

use crate::{
    error::ApiError,
    routes::access::WorkspacePath,
    service::{AsyncJobsQuery, StreamSessionsQuery},
    state::AppState,
};

#[derive(serde::Deserialize)]
pub struct WorkspaceStreamSessionPath {
    pub workspace_id: String,
    pub session_id: String,
}

#[derive(serde::Deserialize)]
pub struct WorkspaceAsyncJobPath {
    pub workspace_id: String,
    pub job_id: String,
}

pub async fn list_protocol_capabilities(
    Path(_path): Path<WorkspacePath>,
    State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
    Ok(Json(json!({
        "items": state.service.list_protocol_capabilities().await
    })))
}

pub async fn list_stream_sessions(
    Path(path): Path<WorkspacePath>,
    Query(query): Query<StreamSessionsQuery>,
    State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
    let page = state
        .service
        .list_stream_sessions(&path.workspace_id.as_str().into(), query.clone())
        .await?;
    Ok(Json(json!({
        "items": page.items,
        "page": query.page.unwrap_or(1),
        "page_size": query.page_size.unwrap_or(20),
        "total": page.total,
    })))
}

pub async fn get_stream_session(
    Path(path): Path<WorkspaceStreamSessionPath>,
    State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
    let session = state
        .service
        .get_stream_session(
            &path.workspace_id.as_str().into(),
            &path.session_id.as_str().into(),
        )
        .await?;
    Ok(Json(json!(session)))
}

pub async fn stop_stream_session(
    Path(path): Path<WorkspaceStreamSessionPath>,
    State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
    let session = state
        .service
        .stop_stream_session(
            &path.workspace_id.as_str().into(),
            &path.session_id.as_str().into(),
        )
        .await?;
    Ok(Json(json!(session)))
}

pub async fn list_async_jobs(
    Path(path): Path<WorkspacePath>,
    Query(query): Query<AsyncJobsQuery>,
    State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
    let page = state
        .service
        .list_async_jobs(&path.workspace_id.as_str().into(), query.clone())
        .await?;
    Ok(Json(json!({
        "items": page.items,
        "page": query.page.unwrap_or(1),
        "page_size": query.page_size.unwrap_or(20),
        "total": page.total,
    })))
}

pub async fn get_async_job(
    Path(path): Path<WorkspaceAsyncJobPath>,
    State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
    let job = state
        .service
        .get_async_job(
            &path.workspace_id.as_str().into(),
            &path.job_id.as_str().into(),
        )
        .await?;
    Ok(Json(json!(job)))
}

pub async fn cancel_async_job(
    Path(path): Path<WorkspaceAsyncJobPath>,
    State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
    let job = state
        .service
        .cancel_async_job(
            &path.workspace_id.as_str().into(),
            &path.job_id.as_str().into(),
        )
        .await?;
    Ok(Json(json!(job)))
}

pub async fn get_async_job_result(
    Path(path): Path<WorkspaceAsyncJobPath>,
    State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
    let result = state
        .service
        .get_async_job_result(
            &path.workspace_id.as_str().into(),
            &path.job_id.as_str().into(),
        )
        .await?;
    Ok(Json(json!(result)))
}
