(ns wanijo.tag.db
  (:require [clojure.spec.alpha :as spec]
            [wanijo.specs :as specs]
            [wanijo.infrastructure.neo4j :as neo4j]))

(spec/def ::name
  (spec/and ::specs/name
            ::specs/no-whitespace))
(spec/def ::tag
  (spec/keys :req-un [::specs/uuid
                      ::specs/created_at
                      ::name]))

(neo4j/defquery tags-by-instance
  "MATCH (i:instance {uuid:{uuid}})-[:tagged_with]->(t:tag)
   RETURN t
   ORDER BY t.name")
(defn tags-by-instance! [instance-uuid]
  {:post [(spec/assert (spec/coll-of ::tag) %)]}
  (map :t
       (neo4j/exec-query! tags-by-instance
                          {:uuid instance-uuid})))

(neo4j/defquery merge-tag
  "MATCH (i:instance {uuid:{instance_uuid}}),
         (u:user {uuid:{user_uuid}})
   MERGE (t:tag {name:{name}})-[:created_by]->(u)
   ON CREATE SET t.uuid = {uuid},
                 t.created_at = {now}
   MERGE (i)-[:tagged_with]->(t)")
(spec/def ::merge-tag-tuple
  (spec/keys :req-un [::specs/instance_uuid
                      ::name
                      ::specs/uuid
                      ::specs/now
                      ::specs/user_uuid]))
(defn merge-tag-tuples [tags instance-uuid user-uuid]
  {:pre  [(spec/assert (spec/coll-of string?) tags)]
   :post [(spec/assert (spec/coll-of (spec/tuple fn? ::merge-tag-tuple))
                       %)]}
  (map (fn [tag-name]
         [merge-tag
          {:instance_uuid instance-uuid
           :name tag-name
           :uuid (neo4j/uuid)
           :now (neo4j/now-str)
           :user_uuid user-uuid}])
       tags))
(comment
  (merge-tag-tuples (list "a" "b")
                    (neo4j/uuid)
                    (neo4j/uuid))
  (spec/explain (spec/coll-of (spec/tuple fn? ::merge-tag-tuple))
                (merge-tag-tuples (list "a" "b")
                                  (neo4j/uuid)
                                  (neo4j/uuid))))
(defn merge-tags! [tags instance-uuid user-uuid]
  (apply neo4j/exec-queries!
         (merge-tag-tuples tags instance-uuid user-uuid)))

(neo4j/defquery remove-tag
  "MATCH (i:instance {uuid:{instance_uuid}})
         -[c:tagged_with]->
         (t:tag {uuid:{uuid}})
   DELETE c")
(defn remove-tag! [uuid instance-uuid]
  (neo4j/exec-query! remove-tag
                     {:instance_uuid instance-uuid
                      :uuid uuid}))
