// Projects API endpoints

use axum::{
    extract::{Path, State},
    http::StatusCode,
    response::IntoResponse,
    Json,
};
use ontoref_derive::onto_api;
use vapora_shared::models::Project;

use crate::api::state::AppState;
use crate::api::ApiResult;

/// List all projects for a tenant
///
/// GET /api/v1/projects
#[onto_api(
    method = "GET",
    path = "/api/v1/projects",
    description = "Returns all projects visible to the authenticated tenant.",
    auth = "bearer",
    actors = "developer, agent, ci, admin",
    tags = "projects, read"
)]
pub async fn list_projects(State(state): State<AppState>) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    let projects = state.project_service.list_projects(tenant_id).await?;
    Ok(Json(projects))
}

/// Get a specific project
///
/// GET /api/v1/projects/:id
#[onto_api(
    method = "GET",
    path = "/api/v1/projects/:id",
    description = "Returns a single project by its identifier.",
    auth = "bearer",
    actors = "developer, agent, ci, admin",
    params = "id:string:required:Project identifier",
    tags = "projects, read"
)]
pub async fn get_project(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    let project = state.project_service.get_project(&id, tenant_id).await?;
    Ok(Json(project))
}

/// Create a new project
///
/// POST /api/v1/projects
#[onto_api(
    method = "POST",
    path = "/api/v1/projects",
    description = "Creates a new project under the authenticated tenant.",
    auth = "bearer",
    actors = "developer, admin",
    tags = "projects, write"
)]
pub async fn create_project(
    State(state): State<AppState>,
    Json(mut project): Json<Project>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    project.tenant_id = "default".to_string();

    let created = state.project_service.create_project(project).await?;
    Ok((StatusCode::CREATED, Json(created)))
}

/// Update a project
///
/// PUT /api/v1/projects/:id
#[onto_api(
    method = "PUT",
    path = "/api/v1/projects/:id",
    description = "Fully replaces a project record with the provided payload.",
    auth = "bearer",
    actors = "developer, admin",
    params = "id:string:required:Project identifier",
    tags = "projects, write"
)]
pub async fn update_project(
    State(state): State<AppState>,
    Path(id): Path<String>,
    Json(updates): Json<Project>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    let updated = state
        .project_service
        .update_project(&id, tenant_id, updates)
        .await?;
    Ok(Json(updated))
}

/// Delete a project
///
/// DELETE /api/v1/projects/:id
#[onto_api(
    method = "DELETE",
    path = "/api/v1/projects/:id",
    description = "Permanently removes a project and all its associated data.",
    auth = "bearer",
    actors = "developer, admin",
    params = "id:string:required:Project identifier",
    tags = "projects, write"
)]
pub async fn delete_project(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    state.project_service.delete_project(&id, tenant_id).await?;
    Ok(StatusCode::NO_CONTENT)
}

/// Add a feature to a project
///
/// POST /api/v1/projects/:id/features
#[onto_api(
    method = "POST",
    path = "/api/v1/projects/:id/features",
    description = "Adds a named feature flag to the specified project.",
    auth = "bearer",
    actors = "developer, admin",
    params = "id:string:required:Project identifier",
    tags = "projects, features, write"
)]
pub async fn add_feature(
    State(state): State<AppState>,
    Path(id): Path<String>,
    Json(payload): Json<serde_json::Value>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    let feature = payload["feature"]
        .as_str()
        .ok_or_else(|| {
            vapora_shared::VaporaError::InvalidInput("Missing 'feature' field".to_string())
        })?
        .to_string();

    let updated = state
        .project_service
        .add_feature(&id, tenant_id, feature)
        .await?;
    Ok(Json(updated))
}

/// Remove a feature from a project
///
/// DELETE /api/v1/projects/:id/features/:feature
#[onto_api(
    method = "DELETE",
    path = "/api/v1/projects/:id/features/:feature",
    description = "Removes a named feature flag from the specified project.",
    auth = "bearer",
    actors = "developer, admin",
    params = "id:string:required:Project identifier; feature:string:required:Feature name",
    tags = "projects, features, write"
)]
pub async fn remove_feature(
    State(state): State<AppState>,
    Path((id, feature)): Path<(String, String)>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    let updated = state
        .project_service
        .remove_feature(&id, tenant_id, &feature)
        .await?;
    Ok(Json(updated))
}

/// Archive a project
///
/// POST /api/v1/projects/:id/archive
#[onto_api(
    method = "POST",
    path = "/api/v1/projects/:id/archive",
    description = "Marks the project as archived, making it read-only.",
    auth = "bearer",
    actors = "developer, admin",
    params = "id:string:required:Project identifier",
    tags = "projects, write"
)]
pub async fn archive_project(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    let updated = state
        .project_service
        .archive_project(&id, tenant_id)
        .await?;
    Ok(Json(updated))
}
