;; #+fw.dump
;; (eval-when (:compile-toplevel :load-toplevel :execute)
;;   (load "~/quicklisp/setup.lisp")
;;   (require :asdf))

;; #+fw.dump
;; (progn
;;   (asdf:load-asd
;;     (asdf:system-relative-pathname :net.didierverna.clon "termio/net.didierverna.clon.termio.asd"))
;;   (require :uiop))

;; #+fw.dump
;; (ql:quickload '(:net.didierverna.clon :ironclad :sqlite :local-time))

(defpackage :fwoar.file-indexer
  (:use :cl)
  (:export
   #:prepare-dump
   #:main))
(in-package :fwoar.file-indexer)

(defparameter +my-format+
  '((:YEAR 4) #\- (:MONTH 2) #\- (:DAY 2) #\Space
    (:HOUR 2) #\: (:MIN 2) #\: (:SEC 2)))

(defun now-time ()
  (local-time:format-timestring nil
                                (local-time:now)
                                :format +my-format+))

(defvar *synopsis*
  (net.didierverna.clon:defsynopsis (:postfix "DB FILES..." :make-default nil)
    (stropt :long-name "ts" :env-var "FWOAR_TX_TS")
    (flag :short-name "h" :long-name "help")))

(defun main ()
  (let* ((context (net.didierverna.clon:make-context :synopsis *synopsis*))
         (net.didierverna.clon:*context* context)
         (ts (or (net.didierverna.clon:getopt :context context
                                              :long-name "ts")
                 (now-time))))
    (format *error-output* "Got ts: ~a~%" ts)
    (cond ((net.didierverna.clon:getopt :context context
                                        :long-name "help")
           (net.didierverna.clon:help))
          (t
           (destructuring-bind (db-fn . files)
               (net.didierverna.clon:remainder :context context)
             (sqlite:with-open-database (db db-fn)
               (sqlite:execute-non-query db "pragma journal_mode=wal")
               (sqlite:execute-non-query
                db
                "create table if not exists
                  files_shasums (file text,
                                 shasum text,
                                 size bigint,
                                 count bigint,
                                 ts datetime default current_timestamp)")
               (sqlite:execute-non-query
                db
                "create unique index if not exists shasums_files_unique_assuc on files_shasums(file,shasum)")
               (loop for raw-file in files
                     for file = (uiop:parse-native-namestring raw-file)
                     do
                        (when (< (random 1000000)
                                 100)
                          (format *error-output* "~&processed: ~a~%" (uiop:native-namestring file)))
                        (sqlite:with-transaction db
                          (with-open-file (s file :element-type '(unsigned-byte 8))
                            (let* ((sum (ironclad:byte-array-to-hex-string
                                         (ironclad:digest-file :sha256 file)))
                                   (length (file-length s)))
                              (sqlite:execute-single db
                                                     "insert into files_shasums (file,shasum,size,count,ts)
                                                      values (?,?,?, 1,?)
                                                      on conflict do update set count = (count + 1),
                                                                                ts = excluded.ts"
                                                     (uiop:native-namestring (truename file))
                                                     sum
                                                     length
                                                     ts)))))))))))

(defun prepare-dump ()
  (setf net.didierverna.clon:*context* nil
        *features* (remove :fw.main (remove :fw.dump *features*))))

#+(or)
(defun dump ()
  (setf net.didierverna.clon:*context* nil
        *features* (remove :fw.dump *features*))
  (net.didierverna.clon:dump "file-indexer" main))