(ns auto-ap.graphql.utils
  (:require [clojure.string :as str]
            [buddy.auth :refer [throw-unauthorized]]
            [clojure.walk :as walk]
            [clojure.tools.logging :as log]))


(defn snake->kebab [s]
  (str/replace s #"_" "-"))

(defn kebab [x]
  (if (qualified-keyword? x)
    (keyword (snake->kebab (namespace x)) (snake->kebab (name x)) )
    (keyword (snake->kebab (name x)))))

(defn kebab->snake [s]
  (str/replace (str/replace s #"-" "_") #"\?$" "" ))

(defn snake [x]
  (keyword (kebab->snake (name x))))

(defn ->graphql [m]
  (walk/postwalk
    (fn [node]
      (cond

        (keyword? node)
        (snake node)

        :else
        node))
    m))

(defn <-graphql [m]
  (walk/postwalk
    (fn [node]
      (cond

        (keyword? node)
        (kebab node)

        :else
        node))
    m))

(defn is-admin? [id]
  (= "admin" (:user/role id)))

(defn assert-admin [id]
  (when-not (= "admin" (:user/role id))
    (log/warn "user " id " not an admin!")
    (throw-unauthorized)))

(defn assert-power-user [id]
  (when-not (#{"power-user" "admin"} (:user/role id))
    (log/warn "user " id " not an power-user!")
    (throw-unauthorized)))

(defn can-see-client? [identity client]
  (when (not client)
    (log/warn "WARNING - permission checking for null client"))
  (or (= "admin" (:user/role identity))
      ((set (map :db/id (:user/clients identity))) (:db/id client))
      ((set (map :db/id (:user/clients identity))) client)))

(defn assert-can-see-client [identity client]
  (when-not (can-see-client? identity client)
    (log/warn "IDENTITY " identity " can not see company " client)
    (throw-unauthorized)))

(defn limited-clients [id]
  (cond
    (or 
    (= (:user/role id) "none"))
    []

    (= (:user/role id) "admin")
    nil

    (#{"manager" "user" "power-user"} (:user/role id))
    (:user/clients id [])))

(defn result->page [results result-count key args]
  {key (map ->graphql results)
   :total result-count
   :count (count results)
   :start (:start args 0)
   :end (+ (:start args 0) (count results))})

(defn ident->enum-f [k]
  #(update % k
           (fn [value] (some-> value :db/ident name keyword))))

(defn enum->keyword [e namespace]
  (some->> e name snake->kebab (keyword namespace)))
