///|
/// Represents the messages processed by the PubSub mediator actor.
pub enum PubSubMsg[PubMsg] {
  Subscribe(String, ActorRef[PubMsg])
  Unsubscribe(String, ActorRef[PubMsg])
  Publish(String, PubMsg)
}

///|
/// Represents the state of the PubSub mediator, tracking active subscribers per topic.
pub struct PubSubState[PubMsg] {
  subscribers : Map[String, Array[ActorRef[PubMsg]]]
}

///|
/// Creates a new empty PubSubState.
pub fn[PubMsg] PubSubState::new() -> PubSubState[PubMsg] {
  { subscribers: Map([]) }
}

///|
/// The actor behavior that processes subscription changes and publishes events.
pub async fn[PubMsg] pubsub_behavior(
  _context : Context,
  state : PubSubState[PubMsg],
  msg : PubSubMsg[PubMsg],
) -> PubSubState[PubMsg] {
  @async.pause()
  match msg {
    Subscribe(topic, sub) => {
      match state.subscribers.get(topic) {
        Some(arr) => arr.push(sub)
        None => state.subscribers.set(topic, [sub])
      }
      state
    }
    Unsubscribe(topic, sub) => {
      match state.subscribers.get(topic) {
        Some(arr) => {
          let new_arr = []
          for s in arr {
            if s.id != sub.id {
              new_arr.push(s)
            }
          }
          state.subscribers.set(topic, new_arr)
        }
        None => ()
      }
      state
    }
    Publish(topic, payload) => {
      match state.subscribers.get(topic) {
        Some(arr) =>
          for sub in arr {
            sub.send(payload)
          }
        None => ()
      }
      state
    }
  }
}

///|
fn _silence_pubsub_warnings(ref_ : ActorRef[Int]) -> Unit {
  let _ = Subscribe("", ref_)
  let _ = Unsubscribe("", ref_)
  let _ = Publish("", 0)
}