{{>licenseInfo}}
package {{modelPackage}}

// model package
import upickle.default._
import java.time.*
import java.time.format.DateTimeFormatter

/**
 * This base class lets us refer to fields in exceptions
 */
class Field(val name : String)

final case class ValidationErrors(
    first: ValidationError,
    remaining: Seq[ValidationError],
    message: String
) extends Exception(message)

object ValidationErrors {
  def apply(first: ValidationError, remaining: Seq[ValidationError]) = {
    val noun = if remaining.isEmpty then "error" else "errors"
    new ValidationErrors(
      first,
      remaining,
      remaining.mkString(s"${remaining.size + 1} $noun found: ${first}", "\n\t", "")
    )
  }
}


final case class ValidationError(path : Seq[Field], message : String) extends Exception(message) {
  override def toString = s"ValidationError for ${path.mkString(".")}: $message"
}

given ReadWriter[ZonedDateTime] = readwriter[String].bimap[ZonedDateTime](
  zonedDateTime => DateTimeFormatter.ISO_INSTANT.format(zonedDateTime),
  str => ZonedDateTime.parse(str, DateTimeFormatter.ISO_INSTANT))

given ReadWriter[LocalDateTime] = readwriter[String].bimap[LocalDateTime](
    zonedDateTime => DateTimeFormatter.ISO_INSTANT.format(zonedDateTime),
    str => LocalDateTime.parse(str, DateTimeFormatter.ISO_INSTANT))

given ReadWriter[LocalDate] = readwriter[String].bimap[LocalDate](
    zonedDateTime => DateTimeFormatter.ISO_INSTANT.format(zonedDateTime),
    str => LocalDate.parse(str, DateTimeFormatter.ISO_INSTANT))

given ReadWriter[OffsetDateTime] = readwriter[String].bimap[OffsetDateTime](
    zonedDateTime => DateTimeFormatter.ISO_INSTANT.format(zonedDateTime),
    str =>  scala.util.Try(OffsetDateTime.parse(str, DateTimeFormatter.ISO_DATE_TIME)).getOrElse(
             OffsetDateTime.parse(str, DateTimeFormatter.ISO_INSTANT)
            )
)