use axum::{
    Json, Router,
    extract::{Path, Query, State},
    http::StatusCode,
    response::IntoResponse,
    routing::{get, post},
};
use serde::Deserialize;

use crate::workspace::{Tier, WorkspaceManager};

pub fn router(manager: WorkspaceManager) -> Router {
    Router::new()
        .route("/", get(list_workspaces))
        .route("/create", post(create_workspace))
        .route("/{id}", get(get_workspace))
        .route("/{id}/handoff", post(handoff))
        .route("/{id}/search", post(add_search))
        .route("/{id}/shortlist", post(add_to_shortlist))
        .route("/{id}/activity", post(log_activity))
        .with_state(manager)
}

#[derive(Deserialize)]
struct ListQuery {
    owner: Option<String>,
    tier: Option<Tier>,
}

async fn list_workspaces(
    State(mgr): State<WorkspaceManager>,
    Query(q): Query<ListQuery>,
) -> impl IntoResponse {
    let workspaces = mgr.list(q.owner.as_deref(), q.tier.as_ref()).await;
    Json(workspaces)
}

#[derive(Deserialize)]
struct CreateRequest {
    name: String,
    description: String,
    owner: String,
    tier: Tier,
}

async fn create_workspace(
    State(mgr): State<WorkspaceManager>,
    Json(req): Json<CreateRequest>,
) -> impl IntoResponse {
    match mgr.create(req.name, req.description, req.owner, req.tier).await {
        Ok(ws) => Ok((StatusCode::CREATED, Json(ws))),
        Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e)),
    }
}

async fn get_workspace(
    State(mgr): State<WorkspaceManager>,
    Path(id): Path<String>,
) -> impl IntoResponse {
    match mgr.get(&id).await {
        Some(ws) => Ok(Json(ws)),
        None => Err((StatusCode::NOT_FOUND, format!("workspace not found: {id}"))),
    }
}

#[derive(Deserialize)]
struct HandoffRequest {
    to_agent: String,
    reason: String,
}

async fn handoff(
    State(mgr): State<WorkspaceManager>,
    Path(id): Path<String>,
    Json(req): Json<HandoffRequest>,
) -> impl IntoResponse {
    match mgr.handoff(&id, &req.to_agent, &req.reason).await {
        Ok(ws) => Ok(Json(ws)),
        Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e)),
    }
}

#[derive(Deserialize)]
struct SearchRequest {
    name: String,
    sql: String,
    agent: String,
}

async fn add_search(
    State(mgr): State<WorkspaceManager>,
    Path(id): Path<String>,
    Json(req): Json<SearchRequest>,
) -> impl IntoResponse {
    match mgr.add_search(&id, req.name, req.sql, &req.agent).await {
        Ok(()) => Ok((StatusCode::OK, "search saved")),
        Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e)),
    }
}

#[derive(Deserialize)]
struct ShortlistRequest {
    dataset: String,
    record_id: String,
    notes: String,
    agent: String,
}

async fn add_to_shortlist(
    State(mgr): State<WorkspaceManager>,
    Path(id): Path<String>,
    Json(req): Json<ShortlistRequest>,
) -> impl IntoResponse {
    match mgr.add_to_shortlist(&id, req.dataset, req.record_id, req.notes, &req.agent).await {
        Ok(()) => Ok((StatusCode::OK, "added to shortlist")),
        Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e)),
    }
}

#[derive(Deserialize)]
struct ActivityRequest {
    action: String,
    detail: String,
    agent: String,
}

async fn log_activity(
    State(mgr): State<WorkspaceManager>,
    Path(id): Path<String>,
    Json(req): Json<ActivityRequest>,
) -> impl IntoResponse {
    match mgr.log_activity(&id, req.action, req.detail, &req.agent).await {
        Ok(()) => Ok((StatusCode::OK, "activity logged")),
        Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e)),
    }
}
