<commit_before>package controllers

import com.google.inject.Inject
import email.{EmailSellerMessageBuilder, EmailMessageBuilder}
import models.CompleteAndConfirmFormModel
import models.CompleteAndConfirmFormModel.AllowGoingToCompleteAndConfirmPageCacheKey
import models.CompleteAndConfirmResponseModel
import models.CompleteAndConfirmViewModel
import models.CompleteAndConfirmFormModel.Form.{ConsentId, MileageId}
import models.K2KCacheKeyPrefix.CookiePrefix
import models.SellerEmailModel
import models.VehicleLookupFormModel
import models.VehicleNewKeeperCompletionCacheKeys
import org.joda.time.DateTime
import org.joda.time.format.ISODateTimeFormat
import play.api.data.{FormError, Form}
import play.api.Logger
import play.api.mvc.{Action, AnyContent, Call, Controller, Request, Result}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import uk.gov.dvla.vehicles.presentation.common
import common.clientsidesession.ClientSideSessionFactory
import common.clientsidesession.CookieImplicits.{RichCookies, RichForm, RichResult}
import common.mappings.TitleType
import common.model.{NewKeeperDetailsViewModel, VehicleAndKeeperDetailsModel}
import common.model.NewKeeperEnterAddressManuallyFormModel
import common.services.{SEND, DateService}
import common.views.helpers.FormExtensions.formBinding
import common.webserviceclients.common.{VssWebEndUserDto, VssWebHeaderDto}
import common.webserviceclients.acquire.{AcquireRequestDto, AcquireResponseDto, AcquireService, KeeperDetailsDto, TitleTypeDto}
import utils.helpers.Config
import views.html.changekeeper.complete_and_confirm

class CompleteAndConfirm @Inject()(webService: AcquireService)(implicit clientSideSessionFactory: ClientSideSessionFactory,
                                                               dateService: DateService,
                                                               config: Config) extends Controller {
  private val cookiesToBeDiscardedOnRedirectAway =
    VehicleNewKeeperCompletionCacheKeys ++ Set(AllowGoingToCompleteAndConfirmPageCacheKey)

  private val EMAIL_SUBJECT = "Test email for the Keeper to Keeper service"

  private[controllers] val form = Form(
    CompleteAndConfirmFormModel.Form.detailMapping
  )

  private final val NoCookiesFoundMessage = "Failed to find new keeper details and or vehicle details in cache" +
    "Now redirecting to vehicle lookup"

  def present = Action { implicit request =>
    canPerform {
      val newKeeperDetailsOpt = request.cookies.getModel[NewKeeperDetailsViewModel]
      val vehicleDetailsOpt = request.cookies.getModel[VehicleAndKeeperDetailsModel]
      (newKeeperDetailsOpt, vehicleDetailsOpt) match {
        case (Some(newKeeperDetails), Some(vehicleAndKeeperDetails)) =>
          Ok(complete_and_confirm(CompleteAndConfirmViewModel(form.fill(),
            vehicleAndKeeperDetails,
            newKeeperDetails,
            isSaleDateBeforeDisposalDate = false),
            dateService)
          )
        case _ =>
          redirectToVehicleLookup(NoCookiesFoundMessage).discardingCookie(AllowGoingToCompleteAndConfirmPageCacheKey)
      }
    }(Redirect(routes.VehicleLookup.present()).discardingCookies(cookiesToBeDiscardedOnRedirectAway))
  }

  def submitWithDateCheck = Action.async { implicit request =>
    canPerform {
      form.bindFromRequest.fold(
        invalidForm => Future.successful {
          val newKeeperDetailsOpt = request.cookies.getModel[NewKeeperDetailsViewModel]
          val vehicleDetailsOpt = request.cookies.getModel[VehicleAndKeeperDetailsModel]
          (newKeeperDetailsOpt, vehicleDetailsOpt) match {
            case (Some(newKeeperDetails), Some(vehicleDetails)) =>
              BadRequest(complete_and_confirm(
                CompleteAndConfirmViewModel(formWithReplacedErrors(invalidForm),
                  vehicleDetails,
                  newKeeperDetails,
                  isSaleDateBeforeDisposalDate = false),
                dateService)
              )
            case _ =>
              Logger.warn("Could not find expected data in cache on dispose submit - now redirecting...")
              Redirect(routes.VehicleLookup.present()).discardingCookies()
          }
        },
        validForm => {
          val newKeeperDetailsOpt = request.cookies.getModel[NewKeeperDetailsViewModel]
          val vehicleLookupOpt = request.cookies.getModel[VehicleLookupFormModel]
          val vehicleDetailsOpt = request.cookies.getModel[VehicleAndKeeperDetailsModel]
          val sellerEmailModelOpt = request.cookies.getModel[SellerEmailModel]
          val validFormResult = (newKeeperDetailsOpt, vehicleLookupOpt, vehicleDetailsOpt, sellerEmailModelOpt) match {
            case (Some(newKeeperDetails), Some(vehicleLookup), Some(vehicleDetails), Some(sellerEmailModel)) =>
              vehicleDetails.keeperEndDate match {
                case Some(keeperEndDate) =>
                  if (keeperEndDate.toLocalDate.isEqual(validForm.dateOfSale) || keeperEndDate.toLocalDate.isBefore(validForm.dateOfSale)) {
                    // The dateOfSale is valid
                    acquireAction(validForm,
                      newKeeperDetails,
                      vehicleLookup,
                      vehicleDetails,
                      sellerEmailModel,
                      request.cookies.trackingId)
                  }
                  else {
                    // The dateOfSale is invalid
                    Future.successful{
                      BadRequest(complete_and_confirm(
                        CompleteAndConfirmViewModel(form.fill(validForm),
                          vehicleDetails,
                          newKeeperDetails,
                          isSaleDateBeforeDisposalDate = true, // This will tell the page to display the date warning
                          submitAction = controllers.routes.CompleteAndConfirm.submitNoDateCheck(), // Next time the submit will not perform any date check
                          dateOfDisposal = Some(keeperEndDate.toString("dd/MM/yyyy")) // Pass the dateOfDisposal so we can tell the user in the warning
                        ), dateService)
                      )
                    }
                  }
                case _ =>
                  acquireAction(validForm,
                    newKeeperDetails,
                    vehicleLookup,
                    vehicleDetails,
                    sellerEmailModel,
                    request.cookies.trackingId)
              }

            case _ => Future.successful {
              Logger.warn("Could not find expected data in cache on dispose submit - now redirecting to VehicleLookup...")
              Redirect(routes.VehicleLookup.present()).discardingCookie(AllowGoingToCompleteAndConfirmPageCacheKey)
            }
          }
          validFormResult
        }
      )
    }(Future.successful(Redirect(routes.VehicleLookup.present()).discardingCookies(cookiesToBeDiscardedOnRedirectAway)))
  }

  def submitNoDateCheck = Action.async { implicit request =>
    canPerform {
      form.bindFromRequest.fold(
        invalidForm => Future.successful {
          val newKeeperDetailsOpt = request.cookies.getModel[NewKeeperDetailsViewModel]
          val vehicleDetailsOpt = request.cookies.getModel[VehicleAndKeeperDetailsModel]
          (newKeeperDetailsOpt, vehicleDetailsOpt) match {
            case (Some(newKeeperDetails), Some(vehicleDetails)) =>
              BadRequest(complete_and_confirm(
                CompleteAndConfirmViewModel(formWithReplacedErrors(invalidForm),
                  vehicleDetails,
                  newKeeperDetails,
                  isSaleDateBeforeDisposalDate = false),
                dateService)
              )
            case _ =>
              Logger.warn("Could not find expected data in cache on dispose submit - now redirecting...")
              Redirect(routes.VehicleLookup.present()).discardingCookies()
          }
        },
        validForm => {
          val newKeeperDetailsOpt = request.cookies.getModel[NewKeeperDetailsViewModel]
          val vehicleLookupOpt = request.cookies.getModel[VehicleLookupFormModel]
          val vehicleDetailsOpt = request.cookies.getModel[VehicleAndKeeperDetailsModel]
          val sellerEmailModelOpt = request.cookies.getModel[SellerEmailModel]
          val validFormResult = (newKeeperDetailsOpt, vehicleLookupOpt, vehicleDetailsOpt, sellerEmailModelOpt) match {
            case (Some(newKeeperDetails), Some(vehicleLookup), Some(vehicleDetails), Some(sellerEmailModel)) =>
              acquireAction(validForm,
                newKeeperDetails,
                vehicleLookup,
                vehicleDetails,
                sellerEmailModel,
                request.cookies.trackingId)
            case _ => Future.successful {
              Logger.warn("Could not find expected data in cache on dispose submit - now redirecting to VehicleLookup...")
              Redirect(routes.VehicleLookup.present())
            }
          }
          validFormResult.map(_.discardingCookie(AllowGoingToCompleteAndConfirmPageCacheKey))
        }
      )
    }(Future.successful(Redirect(routes.VehicleLookup.present()).discardingCookies(cookiesToBeDiscardedOnRedirectAway)))
  }

//  private def canPerformSubmit[R](action: => Future[Result])(implicit request: Request[_]) =
//    request.cookies.getString(AllowGoingToCompleteAndConfirmPageCacheKey).fold {
//      Logger.warn(s"Could not find AllowGoingToCompleteAndConfirmPageCacheKey in the request. " +
//        s"Redirect to VehicleLookup discarding cookies $cookiesToBeDiscardeOnRedirectAway")
//      Future.successful(Redirect(routes.VehicleLookup.present()).discardingCookies(cookiesToBeDiscardeOnRedirectAway))
//    }(c => action)

  private def redirectToVehicleLookup(message: String) = {
    Logger.warn(message)
    Redirect(routes.VehicleLookup.present())
  }

  def back = Action { implicit request =>
    request.cookies.getModel[NewKeeperEnterAddressManuallyFormModel] match {
      case Some(manualAddress) =>
        Redirect(routes.NewKeeperEnterAddressManually.present())
      case None => Redirect(routes.NewKeeperChooseYourAddress.present())<commit_msg>US2470 Made the CompleteAndConfirm controller more DRY<commit_after>package controllers

import com.google.inject.Inject
import email.{EmailSellerMessageBuilder, EmailMessageBuilder}
import models.CompleteAndConfirmFormModel
import models.CompleteAndConfirmFormModel.AllowGoingToCompleteAndConfirmPageCacheKey
import models.CompleteAndConfirmResponseModel
import models.CompleteAndConfirmViewModel
import models.CompleteAndConfirmFormModel.Form.{ConsentId, MileageId}
import models.K2KCacheKeyPrefix.CookiePrefix
import models.SellerEmailModel
import models.VehicleLookupFormModel
import models.VehicleNewKeeperCompletionCacheKeys
import org.joda.time.{DateTime, LocalDate}
import org.joda.time.format.ISODateTimeFormat
import play.api.data.{FormError, Form}
import play.api.Logger
import play.api.mvc.{Action, AnyContent, Call, Controller, Request, Result}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import uk.gov.dvla.vehicles.presentation.common
import common.clientsidesession.ClientSideSessionFactory
import common.clientsidesession.CookieImplicits.{RichCookies, RichForm, RichResult}
import common.mappings.TitleType
import common.model.{NewKeeperDetailsViewModel, VehicleAndKeeperDetailsModel}
import common.model.NewKeeperEnterAddressManuallyFormModel
import common.services.{SEND, DateService}
import common.views.helpers.FormExtensions.formBinding
import common.webserviceclients.common.{VssWebEndUserDto, VssWebHeaderDto}
import common.webserviceclients.acquire.{AcquireRequestDto, AcquireResponseDto, AcquireService, KeeperDetailsDto, TitleTypeDto}
import utils.helpers.Config
import views.html.changekeeper.complete_and_confirm

class CompleteAndConfirm @Inject()(webService: AcquireService)(implicit clientSideSessionFactory: ClientSideSessionFactory,
                                                               dateService: DateService,
                                                               config: Config) extends Controller {
  private val cookiesToBeDiscardedOnRedirectAway =
    VehicleNewKeeperCompletionCacheKeys ++ Set(AllowGoingToCompleteAndConfirmPageCacheKey)

  private val EMAIL_SUBJECT = "Test email for the Keeper to Keeper service"

  private[controllers] val form = Form(
    CompleteAndConfirmFormModel.Form.detailMapping
  )

  private final val NoCookiesFoundMessage = "Failed to find new keeper details and or vehicle details in cache" +
    "Now redirecting to vehicle lookup"

  def present = Action { implicit request =>
    canPerform {
      val newKeeperDetailsOpt = request.cookies.getModel[NewKeeperDetailsViewModel]
      val vehicleDetailsOpt = request.cookies.getModel[VehicleAndKeeperDetailsModel]
      (newKeeperDetailsOpt, vehicleDetailsOpt) match {
        case (Some(newKeeperDetails), Some(vehicleAndKeeperDetails)) =>
          Ok(complete_and_confirm(CompleteAndConfirmViewModel(form.fill(),
            vehicleAndKeeperDetails,
            newKeeperDetails,
            isSaleDateBeforeDisposalDate = false),
            dateService)
          )
        case _ =>
          redirectToVehicleLookup(NoCookiesFoundMessage).discardingCookie(AllowGoingToCompleteAndConfirmPageCacheKey)
      }
    }(Redirect(routes.VehicleLookup.present()).discardingCookies(cookiesToBeDiscardedOnRedirectAway))
  }

  // The dates are valid if they are the same or if the disposal date is before the acquisition date
  def submitWithDateCheck = submitBase(
    (keeperEndDate, dateOfSale) =>
      keeperEndDate.toLocalDate.isEqual(dateOfSale) || keeperEndDate.toLocalDate.isBefore(dateOfSale)
  )

  def submitNoDateCheck = submitBase((keeperEndDate, dateOfSale) => true)

  private def submitBase(validDates: (DateTime, LocalDate) => Boolean) = Action.async { implicit request =>
    canPerform {
      form.bindFromRequest.fold(
        invalidForm => Future.successful {
          val newKeeperDetailsOpt = request.cookies.getModel[NewKeeperDetailsViewModel]
          val vehicleDetailsOpt = request.cookies.getModel[VehicleAndKeeperDetailsModel]
          (newKeeperDetailsOpt, vehicleDetailsOpt) match {
            case (Some(newKeeperDetails), Some(vehicleDetails)) =>
              BadRequest(complete_and_confirm(
                CompleteAndConfirmViewModel(formWithReplacedErrors(invalidForm),
                  vehicleDetails,
                  newKeeperDetails,
                  isSaleDateBeforeDisposalDate = false),
                dateService)
              )
            case _ =>
              Logger.warn("Could not find expected data in cache on dispose submit - now redirecting...")
              Redirect(routes.VehicleLookup.present()).discardingCookies()
          }
        },
        validForm => {
          val newKeeperDetailsOpt = request.cookies.getModel[NewKeeperDetailsViewModel]
          val vehicleLookupOpt = request.cookies.getModel[VehicleLookupFormModel]
          val vehicleDetailsOpt = request.cookies.getModel[VehicleAndKeeperDetailsModel]
          val sellerEmailModelOpt = request.cookies.getModel[SellerEmailModel]
          val validFormResult = (newKeeperDetailsOpt, vehicleLookupOpt, vehicleDetailsOpt, sellerEmailModelOpt) match {
            case (Some(newKeeperDetails), Some(vehicleLookup), Some(vehicleDetails), Some(sellerEmailModel)) =>
              vehicleDetails.keeperEndDate match {
                case Some(keeperEndDate) =>
                  if (validDates(keeperEndDate, validForm.dateOfSale)) {
                    // The dateOfSale is valid
                    acquireAction(validForm,
                      newKeeperDetails,
                      vehicleLookup,
                      vehicleDetails,
                      sellerEmailModel,
                      request.cookies.trackingId)
                  }
                  else {
                    // The dateOfSale is invalid
                    Future.successful{
                      BadRequest(complete_and_confirm(
                        CompleteAndConfirmViewModel(form.fill(validForm),
                          vehicleDetails,
                          newKeeperDetails,
                          isSaleDateBeforeDisposalDate = true, // This will tell the page to display the date warning
                          submitAction = controllers.routes.CompleteAndConfirm.submitNoDateCheck(), // Next time the submit will not perform any date check
                          dateOfDisposal = Some(keeperEndDate.toString("dd/MM/yyyy")) // Pass the dateOfDisposal so we can tell the user in the warning
                        ), dateService)
                      )
                    }
                  }
                case _ =>
                  acquireAction(validForm,
                    newKeeperDetails,
                    vehicleLookup,
                    vehicleDetails,
                    sellerEmailModel,
                    request.cookies.trackingId)
              }

            case _ => Future.successful {
              Logger.warn("Did not find expected cookie data on complete and confirm submit - now redirecting to VehicleLookup...")
              Redirect(routes.VehicleLookup.present()).discardingCookie(AllowGoingToCompleteAndConfirmPageCacheKey)
            }
          }
          validFormResult
        }
      )
    }(Future.successful(Redirect(routes.VehicleLookup.present()).discardingCookies(cookiesToBeDiscardedOnRedirectAway)))
  }

//  private def canPerformSubmit[R](action: => Future[Result])(implicit request: Request[_]) =
//    request.cookies.getString(AllowGoingToCompleteAndConfirmPageCacheKey).fold {
//      Logger.warn(s"Could not find AllowGoingToCompleteAndConfirmPageCacheKey in the request. " +
//        s"Redirect to VehicleLookup discarding cookies $cookiesToBeDiscardeOnRedirectAway")
//      Future.successful(Redirect(routes.VehicleLookup.present()).discardingCookies(cookiesToBeDiscardeOnRedirectAway))
//    }(c => action)

  private def redirectToVehicleLookup(message: String) = {
    Logger.warn(message)
    Redirect(routes.VehicleLookup.present())
  }

  def back = Action { implicit request =>
    request.cookies.getModel[NewKeeperEnterAddressManuallyFormModel] match {
      case Some(manualAddress) =>
        Redirect(routes.NewKeeperEnterAddressManually.present())
      case None => Redirect(routes.NewKeeperChooseYourAddress.present())
{'fraction_non_alphanumeric': 0.071005279603491, 'fraction_numerical': 0.0003232410300614158, 'mean_word_length': 2.8179761415055533, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5615490', 'n_tokens_mistral': 4788, 'n_tokens_neox': 4580, 'n_words': 856}