use axum::extract::State;
use axum::http::StatusCode;
use axum::response::Json;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use mockforge_core::pr_generation::{
PRFileChange, PRFileChangeType, PRGenerator, PRTemplateContext,
};
#[derive(Clone)]
pub struct PRGenerationState {
pub generator: Option<Arc<PRGenerator>>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct GeneratePRRequest {
pub endpoint: String,
pub method: String,
pub breaking_changes: u32,
pub non_breaking_changes: u32,
pub change_summary: String,
pub affected_files: Vec<String>,
pub file_changes: Vec<PRFileChangeRequest>,
pub labels: Option<Vec<String>>,
pub reviewers: Option<Vec<String>>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct PRFileChangeRequest {
pub path: String,
pub content: String,
pub change_type: String,
}
#[derive(Debug, Serialize)]
pub struct GeneratePRResponse {
pub pr_number: Option<u64>,
pub pr_url: Option<String>,
pub branch: Option<String>,
pub success: bool,
pub error: Option<String>,
}
pub async fn generate_pr(
State(state): State<PRGenerationState>,
Json(request): Json<GeneratePRRequest>,
) -> Result<Json<GeneratePRResponse>, StatusCode> {
let generator = state.generator.as_ref().ok_or(StatusCode::SERVICE_UNAVAILABLE)?;
let file_changes: Vec<PRFileChange> = request
.file_changes
.into_iter()
.map(|fc| {
let change_type = match fc.change_type.as_str() {
"create" => PRFileChangeType::Create,
"update" => PRFileChangeType::Update,
"delete" => PRFileChangeType::Delete,
_ => PRFileChangeType::Update,
};
PRFileChange {
path: fc.path,
content: fc.content,
change_type,
}
})
.collect();
let context = PRTemplateContext {
endpoint: request.endpoint,
method: request.method,
breaking_changes: request.breaking_changes,
non_breaking_changes: request.non_breaking_changes,
affected_files: request.affected_files,
change_summary: request.change_summary,
is_breaking: request.breaking_changes > 0,
metadata: std::collections::HashMap::new(),
};
match generator
.create_pr_from_context(
context,
file_changes,
request.labels.unwrap_or_default(),
request.reviewers.unwrap_or_default(),
)
.await
{
Ok(pr_result) => Ok(Json(GeneratePRResponse {
pr_number: Some(pr_result.number),
pr_url: Some(pr_result.url),
branch: Some(pr_result.branch),
success: true,
error: None,
})),
Err(e) => Ok(Json(GeneratePRResponse {
pr_number: None,
pr_url: None,
branch: None,
success: false,
error: Some(e.to_string()),
})),
}
}
pub fn pr_generation_router(state: PRGenerationState) -> axum::Router {
use axum::routing::post;
axum::Router::new()
.route("/api/v1/pr/generate", post(generate_pr))
.with_state(state)
}