package endpoints

import java.lang.System.currentTimeMillis

import akka.actor.ActorSystem
import akka.event.{Logging, LoggingAdapter}
import akka.http.scaladsl.model.HttpRequest
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.RouteResult.Complete
import akka.http.scaladsl.server._
import akka.http.scaladsl.server.directives._
import akka.http.scaladsl.settings.RoutingSettings
import akka.stream.{ActorMaterializer, Materializer}

import scala.concurrent.ExecutionContext

class Endpoints(userEndpoint: UserEndpoint,
                healthCheckEndpoint: HealthCheckEndpoint) {
  def routes(implicit
             sys: ActorSystem,
             mat: ActorMaterializer,
             ec: ExecutionContext) = loggableRoute {
    Route.seal {
      userEndpoint.userRoutes ~ healthCheckEndpoint.healthCheckRoute
    }
  }

  def logRequestAndResponse(loggingAdapter: LoggingAdapter, before: Long)(req: HttpRequest)(res: Any): Unit = {
    val entry = res match {
      case Complete(resp) =>
        val message = s"{path=${req.uri}, method=${req.method.value}, status=${resp.status.intValue()}, elapsedTime=${currentTimeMillis() - before}"
        LogEntry(message, Logging.InfoLevel)
      case other => LogEntry(other, Logging.InfoLevel)
    }

    entry.logTo(loggingAdapter)
  }

  def loggableRoute(route: Route)(implicit m: Materializer,
                                  ex: ExecutionContext,
                                  routingSettings: RoutingSettings): Route = {
    DebuggingDirectives.logRequestResult(LoggingMagnet(log => {
      val requestTimestamp = currentTimeMillis()
      logRequestAndResponse(log, requestTimestamp)
    }))(route)
  }
}