use mini_chat_sdk::RequesterType;
use modkit_macros::domain_model;
use modkit_security::AccessScope;
use time::OffsetDateTime;
use uuid::Uuid;
use crate::domain::llm::Usage;
use crate::domain::model::billing_outcome::BillingDerivation;
use crate::domain::model::quota::{SettlementMethod, SettlementOutcome, SettlementPath};
use crate::infra::db::entity::chat_turn::TurnState;
use crate::infra::db::entity::quota_usage::PeriodType;
#[domain_model]
#[derive(Debug, Clone)]
pub struct FinalizationInput {
pub turn_id: Uuid,
pub tenant_id: Uuid,
pub chat_id: Uuid,
pub request_id: Uuid,
pub user_id: Uuid,
pub requester_type: RequesterType,
pub scope: AccessScope,
pub message_id: Uuid,
pub terminal_state: TurnState,
pub error_code: Option<String>,
pub error_detail: Option<String>,
pub accumulated_text: String,
pub usage: Option<Usage>,
pub provider_response_id: Option<String>,
pub effective_model: String,
pub selected_model: String,
pub reserve_tokens: i64,
pub max_output_tokens_applied: i32,
pub reserved_credits_micro: i64,
pub policy_version_applied: i64,
pub minimal_generation_floor_applied: i32,
pub quota_decision: String,
pub downgrade_from: Option<String>,
pub downgrade_reason: Option<String>,
pub period_starts: Vec<(PeriodType, time::Date)>,
pub web_search_calls: u32,
pub code_interpreter_calls: u32,
pub context_window: u32,
pub assembled_context_tokens: u64,
pub messages_truncated: bool,
pub ttft_ms: Option<u64>,
pub total_ms: Option<u64>,
}
#[domain_model]
#[derive(Debug, Clone)]
pub struct FinalizationOutcome {
pub won_cas: bool,
pub billing_outcome: Option<BillingDerivation>,
pub settlement_outcome: Option<SettlementOutcome>,
}
#[must_use]
pub fn has_known_usage(usage: Option<Usage>) -> bool {
usage.is_some_and(|u| u.input_tokens > 0 || u.output_tokens > 0)
}
#[must_use]
pub fn settlement_path_from_billing(
method: SettlementMethod,
usage: Option<Usage>,
) -> SettlementPath {
match method {
SettlementMethod::Actual => {
let u = usage.unwrap_or_else(|| unreachable!("Actual settlement requires usage"));
SettlementPath::Actual {
input_tokens: u.input_tokens,
output_tokens: u.output_tokens,
}
}
SettlementMethod::Estimated => SettlementPath::Estimated,
SettlementMethod::Released => SettlementPath::Released,
}
}
#[domain_model]
#[derive(Debug, Clone)]
pub struct OrphanFinalizationInput {
pub turn_id: Uuid,
pub tenant_id: Uuid,
pub chat_id: Uuid,
pub request_id: Uuid,
pub user_id: Option<Uuid>,
pub requester_type: RequesterType,
pub effective_model: Option<String>,
pub reserve_tokens: Option<i64>,
pub max_output_tokens_applied: Option<i32>,
pub reserved_credits_micro: Option<i64>,
pub policy_version_applied: Option<i64>,
pub minimal_generation_floor_applied: Option<i32>,
pub started_at: OffsetDateTime,
pub web_search_completed_count: u32,
pub code_interpreter_completed_count: u32,
}