;; I noticed I've been doing a lot of work with time. This is time
;; helpers.

(in-package #:cl-deck-builder2.toolkit.time)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun time-format (when &optional (format local-time:+rfc3339-format+))
  (local-time:format-timestring nil when :format format))

(defun time-format/date-only (when)
  (time-format when local-time:+rfc3339-format/date-only+))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun day- (when &optional (amount 1))
  "Subtract AMOUNT days from WHEN."
  (local-time:timestamp- when amount :day))

(defun day+ (when &optional (amount 1))
  "Add AMOUNT days to  WHEN."
    (local-time:timestamp+ when amount :day))

(defun month- (when &optional (amount 1))
  "Subtract AMOUNT months from WHEN."
  (local-time:timestamp-
   (local-time:timestamp- when amount :month)
   local-time:+seconds-per-day+ :sec))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun time-now ()
  "Today's date, passed through FORMAT-DMY."
  (local-time:now))

(defun time-yesterday ()
  "Yesterday's date, passed through FORMAT-DMY."
  (day- (time-now)))

;; TODO Why am I using this?
(defun time-first-of-month ()
  "The first day of this month." 
  (local-time:timestamp-minimize-part
   (time-now) :day))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun n-month-list (&key (when (time-now)) (start 1) (n 6))
  "Produce a LIST of the last N months, using WHEN as the reference point.
The values iterate numerically from START, that is, the result will be length N - START.
The date will be on the first of each month, in chronological order."
  (mapcar (lambda (n)
            (month- when n))
          (loop for i from start upto n collect i)))

(defun n-day-list (&key (when (time-now)) (start 0) (n 5))
  "Produce a LIST of the last N days, using WHEN as a reference point.
The values will iterate numerically from START, that is, the result will be length N - START.
The exact times will not be modified. The results will be in chronological order."
  (mapcar (lambda (n)
            (day- when n))
          (loop for i from start upto n collect i)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun time-friday (&key (when (time-now)))
  (local-time:adjust-timestamp
      when
    (offset :day-of-week :friday)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun format-status-report (&key (stream *standard-output*) (when (time-friday)))
  (let ((date-str (time-format/date-only when))
        (day-map (reverse
                  (mapcar #'time-format/date-only (n-day-list :when when :n 4)))))
    (format stream
            "#+TITLE: Status Report: Week of ~A~%~%* Status Report: ~
Week of ~A~%~%Total hours: 40 h.~%~%~{** ~A~%~%Hours: 0800A-1600P (8h)~%~%~}"
            date-str date-str day-map)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defparameter *status-report-base-dir*
  (probe-file #P"~/code/cl-deck-builder2/doc/status-report/"))

(defun generate-status-report (&key (when (time-friday)))
  (let ((filespec (merge-pathnames
                   (format nil "~a.org" (time-format/date-only when))
                   *status-report-base-dir*)))
    (with-open-file (f filespec
                      :direction :output
                      :if-exists :error
                      :if-does-not-exist :create)
      (format-status-report :stream f :when when)
      (probe-file filespec))))
