use crate::reality::RealityLevel;
use chrono::{DateTime, Utc};
use mockforge_foundation::protocol::Protocol;
type ChaosScenario = Value;
#[cfg(feature = "data")]
pub use mockforge_data::PersonaGraph;
#[cfg(feature = "data")]
pub use mockforge_data::PersonaProfile;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnifiedState {
pub workspace_id: String,
pub active_persona: Option<PersonaProfile>,
pub active_scenario: Option<String>,
pub reality_level: RealityLevel,
pub reality_continuum_ratio: f64,
pub active_chaos_rules: Vec<ChaosScenario>,
pub entity_state: HashMap<String, EntityState>,
pub protocol_states: HashMap<Protocol, ProtocolState>,
#[cfg(feature = "data")]
#[serde(skip)]
pub persona_graph: Option<PersonaGraph>,
#[cfg(not(feature = "data"))]
#[serde(skip)]
#[allow(dead_code)]
persona_graph: Option<()>,
pub last_updated: DateTime<Utc>,
pub version: u64,
}
impl UnifiedState {
pub fn new(workspace_id: String) -> Self {
Self {
workspace_id,
active_persona: None,
active_scenario: None,
reality_level: RealityLevel::ModerateRealism,
reality_continuum_ratio: 0.0,
active_chaos_rules: Vec::new(),
entity_state: HashMap::new(),
protocol_states: HashMap::new(),
#[cfg(feature = "data")]
persona_graph: Some(PersonaGraph::new()),
#[cfg(not(feature = "data"))]
persona_graph: None,
last_updated: Utc::now(),
version: 1,
}
}
#[cfg(feature = "data")]
pub fn get_or_create_persona_graph(&mut self) -> &mut PersonaGraph {
if self.persona_graph.is_none() {
self.persona_graph = Some(PersonaGraph::new());
}
self.persona_graph.as_mut().unwrap()
}
#[cfg(feature = "data")]
pub fn persona_graph(&self) -> Option<&PersonaGraph> {
self.persona_graph.as_ref()
}
#[cfg(not(feature = "data"))]
pub fn get_or_create_persona_graph(&mut self) -> &mut () {
if self.persona_graph.is_none() {
self.persona_graph = Some(());
}
self.persona_graph.as_mut().unwrap()
}
#[cfg(not(feature = "data"))]
pub fn persona_graph(&self) -> Option<&()> {
self.persona_graph.as_ref()
}
pub fn entity_key(entity_type: &str, entity_id: &str) -> String {
format!("{}:{}", entity_type, entity_id)
}
pub fn get_entity(&self, entity_type: &str, entity_id: &str) -> Option<&EntityState> {
let key = Self::entity_key(entity_type, entity_id);
self.entity_state.get(&key)
}
pub fn register_entity(&mut self, entity: EntityState) {
let key = Self::entity_key(&entity.entity_type, &entity.entity_id);
self.entity_state.insert(key, entity);
self.last_updated = Utc::now();
self.version += 1;
}
pub fn increment_version(&mut self) {
self.version += 1;
self.last_updated = Utc::now();
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EntityState {
pub entity_type: String,
pub entity_id: String,
pub data: Value,
pub seen_in_protocols: Vec<Protocol>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub persona_id: Option<String>,
}
impl EntityState {
pub fn new(entity_type: String, entity_id: String, data: Value) -> Self {
let now = Utc::now();
Self {
entity_type,
entity_id,
data,
seen_in_protocols: Vec::new(),
created_at: now,
updated_at: now,
persona_id: None,
}
}
pub fn mark_seen_by(&mut self, protocol: Protocol) {
if !self.seen_in_protocols.contains(&protocol) {
self.seen_in_protocols.push(protocol);
}
}
pub fn update_data(&mut self, data: Value) {
self.data = data;
self.updated_at = Utc::now();
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProtocolState {
pub protocol: Protocol,
pub active_sessions: Vec<SessionInfo>,
pub config: Value,
pub last_activity: DateTime<Utc>,
}
impl ProtocolState {
pub fn new(protocol: Protocol) -> Self {
Self {
protocol,
active_sessions: Vec::new(),
config: Value::Object(serde_json::Map::new()),
last_activity: Utc::now(),
}
}
pub fn touch(&mut self) {
self.last_activity = Utc::now();
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionInfo {
pub session_id: String,
pub persona_id: Option<String>,
pub created_at: DateTime<Utc>,
pub metadata: HashMap<String, Value>,
}
impl SessionInfo {
pub fn new(session_id: String) -> Self {
Self {
session_id,
persona_id: None,
created_at: Utc::now(),
metadata: HashMap::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum StateChangeEvent {
PersonaChanged {
workspace_id: String,
persona: PersonaProfile,
},
ScenarioChanged {
workspace_id: String,
scenario_id: String,
},
RealityLevelChanged {
workspace_id: String,
level: RealityLevel,
},
RealityRatioChanged {
workspace_id: String,
ratio: f64,
},
EntityCreated {
workspace_id: String,
entity: EntityState,
},
EntityUpdated {
workspace_id: String,
entity: EntityState,
},
ChaosRuleActivated {
workspace_id: String,
rule: ChaosScenario,
},
ChaosRuleDeactivated {
workspace_id: String,
rule_name: String,
},
}
impl StateChangeEvent {
pub fn workspace_id(&self) -> &str {
match self {
StateChangeEvent::PersonaChanged { workspace_id, .. } => workspace_id,
StateChangeEvent::ScenarioChanged { workspace_id, .. } => workspace_id,
StateChangeEvent::RealityLevelChanged { workspace_id, .. } => workspace_id,
StateChangeEvent::RealityRatioChanged { workspace_id, .. } => workspace_id,
StateChangeEvent::EntityCreated { workspace_id, .. } => workspace_id,
StateChangeEvent::EntityUpdated { workspace_id, .. } => workspace_id,
StateChangeEvent::ChaosRuleActivated { workspace_id, .. } => workspace_id,
StateChangeEvent::ChaosRuleDeactivated { workspace_id, .. } => workspace_id,
}
}
}