use std::sync::Arc;
use axum::extract::State;
use axum::Json;
use serde_json::{json, Value};
use tuitbot_core::automation::Runtime;
use crate::account::{require_mutate, AccountContext};
use crate::error::ApiError;
use crate::state::AppState;
use crate::ws::{AccountWsEvent, WsEvent};
pub async fn status(
State(state): State<Arc<AppState>>,
ctx: AccountContext,
) -> Result<Json<Value>, ApiError> {
let runtimes = state.runtimes.lock().await;
let runtime = runtimes.get(&ctx.account_id);
let running = runtime.is_some();
let task_count = runtime.map_or(0, |r| r.task_count());
let capabilities = state.deployment_mode.capabilities();
let can_post = crate::routes::content::can_post_for(&state, &ctx.account_id).await;
let (provider_backend, capability_tier) =
match state.load_effective_config(&ctx.account_id).await {
Ok(config) => {
let tier = tuitbot_core::config::compute_tier(&config, can_post);
(config.x_api.provider_backend, tier)
}
Err(_) => (
String::new(),
tuitbot_core::config::CapabilityTier::Unconfigured,
),
};
Ok(Json(json!({
"running": running,
"task_count": task_count,
"deployment_mode": state.deployment_mode,
"capabilities": capabilities,
"provider_backend": provider_backend,
"can_post": can_post,
"capability_tier": capability_tier,
})))
}
pub async fn start(
State(state): State<Arc<AppState>>,
ctx: AccountContext,
) -> Result<Json<Value>, ApiError> {
require_mutate(&ctx)?;
let mut runtimes = state.runtimes.lock().await;
if runtimes.contains_key(&ctx.account_id) {
return Err(ApiError::Conflict("runtime is already running".to_string()));
}
runtimes.insert(ctx.account_id.clone(), Runtime::new());
let _ = state.event_tx.send(AccountWsEvent {
account_id: ctx.account_id.clone(),
event: WsEvent::RuntimeStatus {
running: true,
active_loops: vec![],
},
});
Ok(Json(json!({"status": "started"})))
}
pub async fn stop(
State(state): State<Arc<AppState>>,
ctx: AccountContext,
) -> Result<Json<Value>, ApiError> {
require_mutate(&ctx)?;
let mut runtimes = state.runtimes.lock().await;
match runtimes.remove(&ctx.account_id) {
Some(mut rt) => {
rt.shutdown().await;
let _ = state.event_tx.send(AccountWsEvent {
account_id: ctx.account_id.clone(),
event: WsEvent::RuntimeStatus {
running: false,
active_loops: vec![],
},
});
Ok(Json(json!({"status": "stopped"})))
}
None => Err(ApiError::Conflict("runtime is not running".to_string())),
}
}