(local { : system : assoc : split : dup : table= : dig } (require :anoia))
(local svc (require :anoia.svc))
(import-macros { :  define-tests : expect : expect= } :anoia.assert)

(fn parse-args [args]
  (match args
    ["-d" path & rest] (assoc (parse-args rest)
                              :out-path path)
    [watched-service path] { : watched-service
                             : path }))

(fn write-changes [path old-tree new-tree]
  (when (not (table= old-tree new-tree))
    (io.stderr:write "new ssh keys\n")
    (each [username pubkeys (pairs new-tree)]
      (with-open [f (assert (io.open (.. path "/" username) :w))]
        ;;  the keys are "1" "2" "3" etc, so pairs not ipairs
        (each [_ k (pairs pubkeys)]
          (f:write k)
          (f:write "\n")))))
  (each [k v (pairs old-tree)]
    (when (not (. new-tree k))
      (os.remove (.. path "/" k))))
  new-tree)

(define-tests
  (local { : file-exists? } (require :anoia))
  (print "running tests")
  (let [tree {
              "dan" ["f1" "f2"]
              "root" ["f1"]
              }
        out-dir (: (assert (io.popen "mktemp -d -p '' fennel-XXXXXXX" :r))  :read "l")]
    ;; if the trees are identical, nothing is written
    (write-changes out-dir tree tree)
    (expect (not (file-exists? (.. out-dir "/dan"))))

    ;; add an entry
    (write-changes out-dir tree (assoc (dup tree) "geoffrey" ["rr"]))
    (expect (file-exists? (.. out-dir "/dan")))
    (expect= (with-open [f (io.open (.. out-dir "/geoffrey"))] (f:read "*a")) "rr\n")

    ;; newly-missing entries are removed
    (write-changes out-dir (assoc (dup tree) "geoffrey" ["rr"]) tree)
    (expect (not (file-exists? (.. out-dir "/geoffrey"))))

    (write-changes out-dir tree {})
    (os.remove out-dir)
    ))

(fn run []
  (let [{: out-path : watched-service : path } (parse-args arg)
        dir (.. watched-service "/.outputs")
        service (assert (svc.open dir))]
    (accumulate [tree {}
                 v (service:events)]
      (write-changes out-path tree (or (service:output path) {})))))


{ : run }