package wow.doge.mygame.subsystems.events

import scala.concurrent.duration._

import akka.actor.typed.ActorRef
import akka.actor.typed.ActorSystem
import akka.actor.typed.LogOptions
import akka.actor.typed.Props
import akka.actor.typed.SpawnProtocol
import akka.actor.typed.SupervisorStrategy
import akka.actor.typed.scaladsl.Behaviors
import akka.util.Timeout
import com.typesafe.scalalogging.{Logger => SLogger}
import org.slf4j.event.Level
import wow.doge.mygame.implicits._
import wow.doge.mygame.subsystems.events.Event
import wow.doge.mygame.subsystems.events.EventBus
import wow.doge.mygame.subsystems.events.TickEvent

class EventsModule(spawnProtocol: ActorSystem[SpawnProtocol.Command]) {
  implicit val s = spawnProtocol.scheduler

  implicit val timeout = Timeout(1.second)

  val eventBusLogger = SLogger[EventBus[_]]

  val playerEventBusTask =
    createEventBus[PlayerEvent]("playerEventBus")

  // val playerCameraEventBusTask =
  //   createEventBus[PlayerCameraEvent]("playerCameraEventBus", Level.DEBUG)

  val tickEventBusTask =
    createEventBus[TickEvent]("tickEventBus", Level.TRACE)

  val mainEventBusTask = createEventBus[Event]("mainEventBus")

  def createEventBus[T](busName: String, logLevel: Level = Level.DEBUG) =
    spawnProtocol.askL(
      SpawnProtocol.Spawn[EventBus.Command[T]](
        Behaviors.logMessages(
          logOptions = LogOptions()
            .withLevel(logLevel)
            .withLogger(eventBusLogger.underlying),
          Behaviors
            .supervise(EventBus[T]())
            .onFailure[Exception](SupervisorStrategy.restart)
        ),
        busName,
        Props.empty,
        _
      )
    )
}

object EventsModule {
  type GameEventBus[T] = ActorRef[EventBus.Command[T]]
}
