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.{LocalDateTime, LocalDate}

 /* maybeSendGift still has some dependencies (in the parameters or
  * environment)
  *
  * - gift service (in order to call the order method)
  * - date time utils.
  *
  * By the principle of least power, let's pass those into the method
  * as functions instead.  let's also use plain values and functions
  * rather than containers of plain values and methods.
  */
 trait EndpointsV3 {
   this: UserServiceComponent with GiftServiceComponent =>
   import EndpointsV3._

   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.id, user.birthday, user.favoriteThing,
                             LocalDateTime.now, giftService.order)
       // build success response
       response <- Future.fromTry(WebApp.mkResponse(gift))
     } yield response

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

 object EndpointsV3 {
   def isToday(birthday: LocalDate, now: => LocalDateTime) =
     now.getDayOfMonth == birthday.getDayOfMonth &&
     now.getMonth == birthday.getMonth

   def maybeSendGift(userId: ID, birthday: LocalDate, favoriteThing: String,
                     now: => LocalDateTime,
                     orderGift: (Long, String) => Future[(String, Option[Long])])
                    (implicit ec: ExecutionContext) = {
     val birthdayToday = isToday(birthday, now)
     if (birthdayToday) orderGift(userId, favoriteThing)
     else Future.successful(("not today", None))
   }
 }