use axum::extract::State;
use axum::response::Json;
use mockforge_chaos::incident_replay::{
IncidentFormatAdapter, IncidentReplayGenerator, IncidentTimeline,
};
use mockforge_chaos::OrchestratedScenario;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::sync::Arc;
#[derive(Clone)]
pub struct IncidentReplayState {
pub generator: Arc<IncidentReplayGenerator>,
}
impl IncidentReplayState {
pub fn new() -> Self {
Self {
generator: Arc::new(IncidentReplayGenerator::new()),
}
}
}
impl Default for IncidentReplayState {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Deserialize)]
pub struct GenerateReplayRequest {
pub timeline: IncidentTimeline,
#[serde(default)]
pub format: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct ImportIncidentRequest {
pub data: Value,
pub format: String,
}
#[derive(Debug, Serialize)]
pub struct ReplayGenerationResponse {
pub success: bool,
pub scenario: OrchestratedScenario,
pub scenario_json: String,
pub scenario_yaml: String,
}
pub async fn generate_replay(
State(state): State<IncidentReplayState>,
Json(request): Json<GenerateReplayRequest>,
) -> Result<Json<Value>, String> {
let generator = &state.generator;
let scenario = generator.generate_scenario(&request.timeline);
let scenario_json = generator
.export_scenario_to_json(&scenario)
.map_err(|e| format!("Failed to export scenario to JSON: {}", e))?;
let scenario_yaml = generator
.export_scenario_to_yaml(&scenario)
.map_err(|e| format!("Failed to export scenario to YAML: {}", e))?;
Ok(Json(json!({
"success": true,
"scenario": scenario,
"scenario_json": scenario_json,
"scenario_yaml": scenario_yaml,
})))
}
pub async fn import_incident(
State(_state): State<IncidentReplayState>,
Json(request): Json<ImportIncidentRequest>,
) -> Result<Json<Value>, String> {
let timeline = match request.format.as_str() {
"pagerduty" => IncidentFormatAdapter::from_pagerduty(&request.data)
.map_err(|e| format!("Failed to parse PagerDuty format: {}", e))?,
"datadog" => IncidentFormatAdapter::from_datadog(&request.data)
.map_err(|e| format!("Failed to parse Datadog format: {}", e))?,
"custom" => {
serde_json::from_value::<IncidentTimeline>(request.data)
.map_err(|e| format!("Failed to parse custom format: {}", e))?
}
_ => return Err(format!("Unsupported format: {}", request.format)),
};
Ok(Json(json!({
"success": true,
"timeline": timeline,
})))
}
pub async fn import_and_generate(
State(state): State<IncidentReplayState>,
Json(request): Json<ImportIncidentRequest>,
) -> Result<Json<Value>, String> {
let timeline = match request.format.as_str() {
"pagerduty" => IncidentFormatAdapter::from_pagerduty(&request.data)
.map_err(|e| format!("Failed to parse PagerDuty format: {}", e))?,
"datadog" => IncidentFormatAdapter::from_datadog(&request.data)
.map_err(|e| format!("Failed to parse Datadog format: {}", e))?,
"custom" => serde_json::from_value::<IncidentTimeline>(request.data)
.map_err(|e| format!("Failed to parse custom format: {}", e))?,
_ => return Err(format!("Unsupported format: {}", request.format)),
};
let generator = &state.generator;
let scenario = generator.generate_scenario(&timeline);
let scenario_json = generator
.export_scenario_to_json(&scenario)
.map_err(|e| format!("Failed to export scenario to JSON: {}", e))?;
let scenario_yaml = generator
.export_scenario_to_yaml(&scenario)
.map_err(|e| format!("Failed to export scenario to YAML: {}", e))?;
Ok(Json(json!({
"success": true,
"timeline": timeline,
"scenario": scenario,
"scenario_json": scenario_json,
"scenario_yaml": scenario_yaml,
})))
}