package app

import app.actors._
import app.syntax._
import cats.Functor
import cats.effect.{Clock, Concurrent}
import cats.syntax.applicative._
import cats.syntax.flatMap._
import cats.syntax.functor._

object auth {
  def requestNewAuthToken[F[_]](
    implicit F: Functor[F],
    clock: Clock[F]
  ): F[AuthToken] =
    clock.now.map(now => AuthToken(now.plusSeconds(3600), "token"))

  def requestActiveAuthToken[F[_]](
    implicit F: Concurrent[F],
    clock: Clock[F]
  ): F[F[AuthToken]] =
    actor[F, Option[AuthToken], AuthToken](
      initialState = None,
      receive = ref =>
        for {
          existingAuthToken <- ref.get
          now <- clock.now
          authToken <- existingAuthToken
            .filter(_.isActive(now))
            .map(_.pure[F])
            .getOrElse {
              for {
                newAuthToken <- requestNewAuthToken
                _ <- ref.set(Some(newAuthToken))
              } yield newAuthToken
            }
        } yield authToken
    )
}