use axum::{ Json, extract::{Path, State}, http::StatusCode, response::IntoResponse, }; use chrono::Utc; use uuid::Uuid; use domain::{self, DomainError}; use crate::{ dto::ScheduleResponse, error::ApiError, extractors::CurrentUser, state::AppState, }; use super::require_owner; /// Trigger 48-hour schedule generation for a channel, starting from now. /// Replaces any existing schedule for the same window. pub(super) async fn generate_schedule( State(state): State, CurrentUser(user): CurrentUser, Path(channel_id): Path, ) -> Result { let channel = state.channel_service.find_by_id(channel_id).await?; require_owner(&channel, user.id)?; let schedule = state .schedule_engine .generate_schedule(channel_id, Utc::now()) .await?; let _ = state.event_tx.send(domain::DomainEvent::ScheduleGenerated { channel_id, schedule: schedule.clone(), }); Ok((StatusCode::CREATED, Json(ScheduleResponse::from(schedule)))) } /// Return the currently active 48-hour schedule for a channel. /// 404 if no schedule has been generated yet — call POST /:id/schedule first. pub(super) async fn get_active_schedule( State(state): State, CurrentUser(user): CurrentUser, Path(channel_id): Path, ) -> Result { let channel = state.channel_service.find_by_id(channel_id).await?; require_owner(&channel, user.id)?; let schedule = state .schedule_engine .get_active_schedule(channel_id, Utc::now()) .await? .ok_or(DomainError::NoActiveSchedule(channel_id))?; Ok(Json(ScheduleResponse::from(schedule))) }