import gleam/erlang/process
import gleam/otp/actor

pub const call_timeout = 1000

pub type Manager(resp_type, msg_type) {
  Manager(subject: process.Subject(Request(resp_type, msg_type)))
}

pub type State(state_type) {
  State(internal: state_type)
}

pub type Request(resp_type, msg_type) {
  Request(reply_to: process.Subject(resp_type), msg: msg_type)
}

pub fn new(
  init_state: fn() -> state_type,
  handle: fn(Request(resp_type, msg_type), State(state_type)) ->
    actor.Next(Request(resp_type, msg_type), State(state_type)),
) -> Manager(resp_type, msg_type) {
  let assert Ok(subject) = actor.start(State(init_state()), handle)

  Manager(subject)
}

pub fn call(manager: Manager(resp_type, msg_type), msg: msg_type) -> resp_type {
  actor.call(manager.subject, Request(_, msg), call_timeout)
}
