... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.

(.require
 [library
  [lux (.except)
   [abstract
    [monad (.only do)]]
   [control
    ["<>" projection (.use "[1]#[0]" functor)]
    ["[0]" io]
    ["[0]" try]
    ["[0]" exception (.only Exception)]]
   [data
    [text
     ["%" \\injection]]]
   ["[0]" meta (.only)
    ["[0]" code (.only)
     ["<[1]>" \\projection (.only Projection)]]
    [macro
     ["[0]" syntax]
     ["[0]" template]]]
   [world
    [time
     ["[0]" instant]
     ["[0]" date (.only Date) (.use "[1]#[0]" order)]]]]])

(exception.the .public (must_remember [deadline today message focus])
  (Exception [Date Date Text (Maybe Code)])
  (exception.report
   (list ["Deadline" (date.as_text deadline)]
         ["Today" (date.as_text today)]
         ["Message" message]
         ["Code" (when focus
                   {.#Some focus}
                   (code.as_text focus)

                   {.#None}
                   "")])))

(the deadline
  (Projection Date)
  (all <>.either
       (<>#each (|>> instant.of_millis instant.date)
                <code>.integer)
       (do <>.monad
         [raw <code>.text]
         (when (of date.format projection raw)
           {try.#Success date}
           (in date)
           
           {try.#Failure message}
           (<>.failure message)))))

(the .public remember
  (syntax.macro (_ [deadline ..deadline
                    message <code>.text
                    focus (<>.maybe <code>.any)])
    (let [now (io.value instant.now)
          today (instant.date now)]
      (if (date#< deadline today)
        (in (when focus
              {.#Some focus}
              (list focus)

              {.#None}
              (list)))
        (meta.failure (exception.error ..must_remember [deadline today message focus]))))))

(template.with [<name> <message>]
  [(`` (the .public <name>
         (syntax.macro (_ [deadline ..deadline
                           message <code>.text
                           focus (<>.maybe <code>.any)])
           (in (list (` (..remember (, (code.text (date.as_text deadline)))
                          (, (code.text (%.message <message> " " message)))
                          (,* (when focus
                                {.#Some focus}
                                (list focus)

                                {.#None}
                                (list))))))))))]

  [to_do  "TODO"]
  [fix_me "FIXME"]
  )
