use axum::{
    extract::{Path, State},
    http::StatusCode,
    routing::{get, put},
    Json, Router,
};

use crate::AppState;
use theseus_core::*;

pub(crate) fn router() -> Router<AppState> {
    Router::new()
        .route(
            "/api/projects/:project_id/credentials",
            get(list_credentials).post(create_credential),
        )
        .route(
            "/api/projects/:project_id/credentials/:credential_id",
            put(update_credential).delete(delete_credential),
        )
}

async fn list_credentials(
    State(state): State<AppState>,
    Path(project_id): Path<String>,
) -> Result<Json<ApiResponse<Vec<Credential>>>, StatusCode> {
    let pid = crate::resolve_project_id(&state.db, &project_id).await?;
    let creds = state
        .db
        .list_credentials(pid)
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    Ok(Json(ApiResponse::ok(creds)))
}

async fn create_credential(
    State(state): State<AppState>,
    Path(project_id): Path<String>,
    Json(payload): Json<CreateCredentialRequest>,
) -> Result<(StatusCode, Json<ApiResponse<Credential>>), StatusCode> {
    let pid = crate::resolve_project_id(&state.db, &project_id).await?;

    // Validate source_node_id if provided
    if let Some(ref node_id) = payload.source_node_id {
        let nid = *node_id;
        let exists = state
            .db
            .node_exists(pid, nid)
            .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
        if !exists {
            return Err(StatusCode::BAD_REQUEST);
        }
    }

    let cred = state
        .db
        .create_credential(pid, &payload)
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    Ok((StatusCode::CREATED, Json(ApiResponse::ok(cred))))
}

async fn update_credential(
    State(state): State<AppState>,
    Path((project_id, credential_id)): Path<(String, String)>,
    Json(payload): Json<UpdateCredentialRequest>,
) -> Result<Json<ApiResponse<Credential>>, StatusCode> {
    let pid = crate::resolve_project_id(&state.db, &project_id).await?;
    let cid = crate::parse_uuid(&credential_id)?;
    let cred = state
        .db
        .update_credential(pid, cid, &payload)
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
        .ok_or(StatusCode::NOT_FOUND)?;
    Ok(Json(ApiResponse::ok(cred)))
}

async fn delete_credential(
    State(state): State<AppState>,
    Path((project_id, credential_id)): Path<(String, String)>,
) -> Result<Json<ApiResponse<()>>, StatusCode> {
    let pid = crate::resolve_project_id(&state.db, &project_id).await?;
    let cid = crate::parse_uuid(&credential_id)?;
    state
        .db
        .delete_credential(pid, cid)
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    Ok(Json(ApiResponse::ok(())))
}
