             [salava.badge.main :as b]
             [salava.core.helper :refer [dump]]
             [clojure.set :as s]
-            [medley.core :refer [distinct-by]]))
-
-(def no-of-days-in-cache 30)
-
-(defonce metabadge-cache-storage (atom (-> {} (cache/lru-cache-factory :threshold 100) (cache/ttl-cache-factory :ttl (* (* 86400 1000) no-of-days-in-cache)))))
-(defonce user-badge-cache-storage (atom (-> {} (cache/lru-cache-factory :threshold 500) (cache/ttl-cache-factory :ttl (* 86400 1000)))))
+            [medley.core :refer [distinct-by]]
+            [yesql.core :refer [defqueries]]))
+
+(defqueries "sql/metabadge/queries.sql")
+
+(def no-of-days-in-cache 3)
+
+(defonce metabadge-cache-storage (atom (-> {} (cache/lru-cache-factory :threshold 200) (cache/ttl-cache-factory :ttl (* (* 86400 1000) no-of-days-in-cache)))))
+;(defonce user-badge-cache-storage (atom (-> {} (cache/lru-cache-factory :threshold 500) (cache/ttl-cache-factory :ttl (* 86400 1000)))))
 
 (defn url? [s]
   (not (clojure.string/blank? (re-find #"^http" (str s)))))



(defn get-badge-data [ctx badge]
  (let [id (:id badge)
        key (keyword id)]
    (cache/lookup (swap! metabadge-cache-storage
                         #(if (cache/has? % key)
                            (cache/hit % key)
                            (cache/miss % key (public-badge-info ctx id)))) key)))

(defn- expand-required-badges [ctx badges assertion-url]
  (->> badges
       (r/map (fn [b] (-> b (assoc :badge-info (dissoc (get-badge-data ctx b) :language :alt_language :tags :id)
                              :current (= (:url b) assertion-url)
                              :user_badge (db/user-badge-by-assertion ctx (:url b))))) )
       (r/foldcat)))


(defn- process-metabadge [ctx metabadge assertion-url]
  (->> (:metabadge metabadge)
       (r/map (fn [m] (-> m
                          (assoc :required_badges (expand-required-badges ctx (:required_badges m) assertion-url)
                            :milestone? (= assertion-url (get-in m [:badge :url])))
                          (update-in [:badge] merge (dissoc (get-badge-data ctx (:badge m)) :language :alt_language :tags :id)))))
       (r/foldcat)
       (assoc metabadge :metabadge)))

(defn check-metabadge [ctx assertion-url]
  (let [meta-data-url (str (get-in ctx [:config :factory :url]) "/v1/assertion/metabadge/?url=" (u/url-encode assertion-url))]

    (if-let [check (string/starts-with? assertion-url (get-in ctx [:config :factory :url]))]
      (try
        (if-let [metabadge (fetch-json-data meta-data-url)]
          (let [processed-metabadge (process-metabadge ctx  metabadge assertion-url)]
            (if (empty? (:metabadge processed-metabadge)) nil processed-metabadge))
          nil)
        (catch Exception e
          (log/error (str "Did not get metabadge information: " assertion-url))

          nil))
      nil)))

(defn metabadge->badge-map [ctx badge-id]
  (some-> (select-received-metabadge-by-badge-id {:id badge-id} (u/get-db ctx)) first))

(defn pending-metabadge? [ctx pending-assertion id]
  (if-let [is-metabadge? (db/metabadge?! (:connection (u/get-db ctx)) (get-in ctx [:config :factory :url]) (-> pending-assertion (assoc :id id)))]
    (let [badge (metabadge->badge-map ctx id)]
      (db/get-metabadge! ctx (:connection (u/get-db ctx)) (get-in ctx [:config :factory :url]) badge))))


(defn completed-metabadges [ctx user_id]
  (let [metabadges (select-completed-metabadges {:user_id user_id} (u/get-db ctx))]
    (->> metabadges (expand-required-badges-db ctx user_id nil))))

(defn metabadges-in-progress [ctx user_id]
  (let [metabadges (->> (select-all-user-metabadges {:user_id user_id} (u/get-db ctx)) (expand-required-badges-db ctx user_id nil))
        completed-metabadges (completed-metabadges ctx user_id)]
    (remove (fn [m] (some #(= (:metabadge_id %) (:id m)) completed-metabadges)) metabadges)))

(defn all-metabadges [ctx user_id]
  {:in_progress (metabadges-in-progress ctx user_id)
   :completed (completed-metabadges ctx user_id)})

(defn is-metabadge? [ctx user_badge_id]
  (let [x (some-> (select-metabadge-info-from-user-badge {:id user_badge_id} (u/get-db ctx)) first)]
    (reduce-kv (fn [r k v]
                 (assoc r k (if (clojure.string/blank? v) false true))) {} x)))

(defn is-received-metabadge? [ctx user_id metabadge_id]
  (let [check (select-user-received-metabadge-by-metabadge-id {:metabadge_id metabadge_id :user_id user_id} (u/get-db ctx))]
    (if (empty? check) false true)))

(defn metabadge-helper [ctx user_badge_id user_id metabadge_ids]
  (reduce (fn [r id]
            (conj r
                  (if-let [received-metabadge? (is-received-metabadge? ctx user_id id)]
                    (->> (select-completed-metabadge-by-metabadge-id {:user_id user_id :metabadge_id id} (u/get-db ctx)) (expand-required-badges-db ctx user_id user_badge_id))
                    (->> (select-factory-metabadge {:id id} (u/get-db ctx)) (expand-required-badges-db ctx user_id user_badge_id))))) [] metabadge_ids))

(defn get-metabadge [ctx user_badge_id user_id]
  (if-let [check (empty? (is-metabadge? ctx user_badge_id))]
    {}
    (let [user_id (if (nil? user_id) (some-> (select-user-id-by-user-badge-id {:id user_badge_id} (u/get-db ctx)) first :user_id) user_id)
          milestones (->> (select-completed-metabadge-by-badge-id {:user_id user_id :user_badge_id user_badge_id} (u/get-db ctx)) (expand-required-badges-db ctx user_id nil))
          required-in (->> (select-required-metatabadge-by-badge-id {:id user_badge_id} (u/get-db ctx))
                           (map :metabadge_id)
                           (metabadge-helper ctx user_badge_id user_id)
                           flatten)]
      {:milestones milestones :required-in required-in})))



