... 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/.

(.using
 [library
  [lux (.except)
   [abstract
    ["<>" projection (.use "[1]:[0]" functor)]
    ["[0]" monad]]
   [control
    ["[0]" io]]
   [error
    ["[0]" try]
    ["[0]" exception (.only Exception)]]
   [data
    [text
     ["%" \\injection]]
    [collection
     ["[0]" list
      ["?[1]" \\projection]]]]
   [macro
    ["[0]" syntax]
    ["[0]" template]]
   ["[0]" meta (.only)
    ["[0]" code (.only)
     ["<[1]>" \\projection (.only Projection)]]]
   [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)
       (monad.let <>.monad
         [raw <code>.text]
         (when (by date.text of raw)
           {try.:Success date}
           (pure date)
           
           {try.:Failure message}
           (<>.failure message)))))

(syntax.the .public (remember [deadline ..deadline
                               message <code>.text
                               focus (<>.maybe ?list.any)])
  (let [now (io.value instant.now)
        today (instant.date now)]
    (if (date:< deadline today)
        (exec
          (.log!# (text "REMEMBER:"
                        " By " (date.as_text deadline)
                        " " message))
          (pure (when focus
                  {.:Some focus}
                  (list focus)

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

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

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

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