             [taoensso.timbre :as timbre]
             [compojure.core :as compojure :refer (ANY OPTIONS DELETE)]
             [liberator.core :refer (defresource by-method)]
+            [clojure.walk :refer (keywordize-keys)]
             [schema.core :as schema]
             [oc.lib.schema :as lib-schema]
             [oc.lib.db.pool :as pool]

    
    true)) ; no existing entry, so this will fail existence check later

(defn- entry-list-for-board
  "Retrieve an entry list for the board, or false if the org or board doesn't exist."
  [conn org-slug board-slug-or-uuid ctx]

                                                  (-> ctx :user :user-id)
                                                  :secure))))

(defresource follow-up-list [conn org-slug board-slug entry-uuid]
  (api-common/open-company-authenticated-resource config/passphrase) ; verify validity and presence of required JWToken
  :allowed-methods [:options :post]

  ;; Authorization
  :allowed? (by-method {
    :options true
    :post (fn [ctx] (access/allow-authors conn org-slug board-slug (:user ctx)))})

  ;; Media type client accepts
  :available-media-types (by-method {
                            :post [mt/entry-media-type]})
  :handle-not-acceptable (by-method {
                            :post (api-common/only-accept 406 mt/entry-media-type)})

  ;; Media type client sends
  :known-content-type? (by-method {
                          :options true
                          :post (fn [ctx] (api-common/known-content-type? ctx mt/follow-up-media-type))})

  ;; Data handling
  :new? false
  :respond-with-entity? true

  ;; Validations
  :processable? (by-method {
    :options true
    :post (fn [ctx] (valid-follow-up-request? conn entry-uuid (:data ctx) (:user ctx)))})

  ;; Existentialism
  :can-post-to-missing? false
  :exists? (fn [ctx] (if-let* [_slugs? (and (slugify/valid-slug? org-slug)
                                            (slugify/valid-slug? board-slug))
                               org (or (:existing-org ctx)
                                       (org-res/get-org conn org-slug))
                               org-uuid (:uuid org)
                               entry (or (:existing-entry ctx)
                                         (entry-res/get-entry conn entry-uuid))
                               board (board-res/get-board conn (:board-uuid entry))
                               _matches? (and (= org-uuid (:org-uuid entry))
                                              (= org-uuid (:org-uuid board))
                                              (= :published (keyword (:status entry)))) ; sanity check
                               comments (or (:existing-comments ctx)
                                            (entry-res/list-comments-for-entry conn (:uuid entry)))
                               reactions (or (:existing-reactions ctx)
                                             (entry-res/list-reactions-for-entry conn (:uuid entry)))]
                        {:existing-org (api-common/rep org) :existing-board (api-common/rep board)
                         :existing-entry (api-common/rep entry) :existing-comments (api-common/rep comments)
                         :existing-reactions (api-common/rep reactions)}
                        false))

  ;; Actions
  :post! (fn [ctx] (create-follow-ups conn ctx (s/join " " [org-slug board-slug entry-uuid])))

  ;; Responses
  :handle-ok (fn [ctx] (entry-rep/render-entry (:existing-org ctx)
                                               (:existing-board ctx)
                                               (:updated-entry ctx)
                                               (:existing-comments ctx)
                                               (reaction-res/aggregate-reactions (:existing-reactions ctx))
                                               (:access-level ctx)
                                               (-> ctx :user :user-id)))
  :handle-unprocessable-entity (fn [ctx]
    (api-common/unprocessable-entity-response (map #(schema/check common-res/FollowUp %) (:follow-ups ctx)))))

(defresource follow-up [conn org-slug board-slug entry-uuid follow-up-uuid]
  (api-common/open-company-authenticated-resource config/passphrase) ; verify validity and presence of required JWToken
  :allowed-methods [:options :post]

  ;; Authorization
  :allowed? (by-method {
    :options true
    :post (fn [ctx] (access/allow-authors conn org-slug board-slug (:user ctx)))})

  ;; Media type client accepts
  :available-media-types (by-method {
                            :post [mt/entry-media-type]})
  :handle-not-acceptable (by-method {
                            :post (api-common/only-accept 406 mt/entry-media-type)})

  ;; Data handling
  :new? false
  :respond-with-entity? true

  ;; Validations
  :processable? true

  ;; Existentialism
  :can-post-to-missing? false
  :exists? (fn [ctx] (if-let* [_slugs? (and (slugify/valid-slug? org-slug)
                                            (slugify/valid-slug? board-slug))
                               org (or (:existing-org ctx)
                                       (org-res/get-org conn org-slug))
                               org-uuid (:uuid org)
                               entry (or (:existing-entry ctx)
                                         (entry-res/get-entry conn entry-uuid))
                               board (board-res/get-board conn (:board-uuid entry))
                               follow-up (first (filter #(= (:uuid %) follow-up-uuid) (:follow-ups entry)))
                               _matches? (and (= org-uuid (:org-uuid entry))
                                              (= org-uuid (:org-uuid board))
                                              (= :published (keyword (:status entry)))) ; sanity check
                               comments (or (:existing-comments ctx)
                                            (entry-res/list-comments-for-entry conn (:uuid entry)))
                               reactions (or (:existing-reactions ctx)
                                             (entry-res/list-reactions-for-entry conn (:uuid entry)))]
                        {:existing-org (api-common/rep org) :existing-board (api-common/rep board)
                         :existing-entry (api-common/rep entry)
                         :existing-follow-up (api-common/rep follow-up)
                         :existing-comments (api-common/rep comments)
                         :existing-reactions (api-common/rep reactions)}
                        false))

  ;; Actions
  :post! (fn [ctx] (mark-complete-follow-up conn ctx (s/join " " [org-slug board-slug entry-uuid])))

  ;; Responses
  :handle-ok (fn [ctx] (entry-rep/render-entry (:existing-org ctx)
                                               (:existing-board ctx)
                                               (:updated-entry ctx)
                                               (:existing-comments ctx)
                                               (reaction-res/aggregate-reactions (:existing-reactions ctx))
                                               (:access-level ctx)
                                               (-> ctx :user :user-id)))
  :handle-unprocessable-entity (fn [ctx]
    (api-common/unprocessable-entity-response (map #(schema/check common-res/FollowUp %) (:follow-ups ctx)))))

;; ----- Routes -----

(defn routes [sys]
