package com.eddsteel.posts.leastpower
package endpoints

import model._
import services._
import webapp.{Request, Response, NotFoundException}

import scala.concurrent.{ExecutionContext, Future}
import scala.util.Try
import java.time.LocalDate

/** Let's change the test to ignore the request/response/routing stuff and just test the business logic.
  *
  * It would be easier to test this logic if we made the dependencies
  * explicit (method params), and moved it out to the companion object.
  */
trait EndpointsV2 {
  this: UserServiceComponent with GiftServiceComponent =>
  import EndpointsV2._

  def postGift(req: Request)(implicit ec: ExecutionContext): Future[Response] = {
    val response = for {
      // extract ID from request path
      userId <- Future.fromTry(WebApp.extractAndValidateUserId(req))
      // retrieve the user
      maybeUser <- userService.getById(userId)
      // bail with 404 if we have no user.
      user = maybeUser.getOrElse(throw NotFoundException(userId))
      // check if it's the user's birthday, and maybe send them a gift.
      gift <- maybeSendGift(user, giftService)
      // build success response
      response <- Future.fromTry(WebApp.mkResponse(gift))
    } yield response

    // build error response
    response.recover(WebApp.mkErrorResponse)
  }
}

object EndpointsV2 {
  private def isToday(birthday: LocalDate): Boolean = {
    // using this utility helps us write tests.
    val today = DateTimeUtils.now.toLocalDate

    today.getDayOfMonth == birthday.getDayOfMonth &&
    today.getMonth == birthday.getMonth
  }

  private[endpoints] def maybeSendGift(user: User, giftService: GiftService) = {
    val birthdayToday = isToday(user.birthday)
    if (birthdayToday) giftService.order(user.id, user.favoriteThing)
    else Future.successful(("not today", None))
  }
}