(in-package #:lispsearch/test)

;;;; DB layer: migration, upserts, FTS5 ranking + triggers, name/GLOB search.
;;;; (was test/m1-db.lisp)

(define-test db-migrate :parent offline
  (with-fresh-db (db)
    (finish (progn (ls:migrate db) (ls:migrate db)) "migrate is idempotent")
    (is string= ls::+schema-version+ (ls:meta-get db "schema_version"))))

(define-test db-upsert-name-dedupes :parent offline
  (with-fresh-db (db)
    (ls:upsert-name db "trivial-features" "trivial-features")
    (ls:upsert-name db "trivial-features" "trivial-features") ; dup no-op
    (is = 1 (sqlite:execute-single db "SELECT COUNT(*) FROM system"))))

(define-test db-counts :parent offline
  (with-fresh-db (db)
    (ls:upsert-name db "trivial-features" "trivial-features")
    (load-sample db)
    (is = 5 (sqlite:execute-single db "SELECT COUNT(*) FROM system")
        "4 enriched + 1 tier-1")
    (is = 4 (getf (ls:stats db) :enriched))))

(define-test db-fts-html-parser :parent offline
  (with-fresh-db (db)
    (load-sample db)
    (let* ((rows (ls:search-fts db "html parser"))
           (names (mapcar #'first rows)))
      (true (>= (length rows) 2) "fts returns >=2 hits")
      (true (member "cl-html5-parser" names :test #'string=))
      (true (member "plump" names :test #'string=))
      (false (member "cl-ppcre" names :test #'string=) "excludes non-matches")
      (let ((ranks (mapcar (lambda (r) (nth 4 r)) rows)))
        (true (every #'<= ranks (rest ranks)) "rank ascending (best first)")))))

(define-test db-fts-prefix :parent offline
  (with-fresh-db (db)
    (load-sample db)
    (true (>= (length (ls:search-fts db "pars*")) 2) "prefix 'pars*' matches parsers")))

(define-test db-name-glob :parent offline
  (with-fresh-db (db)
    (load-sample db)
    (let ((names (mapcar #'first (ls:search-name db "cl-*"))))
      (true (member "cl-ppcre" names :test #'string=))
      (true (member "cl-html5-parser" names :test #'string=))
      (false (member "plump" names :test #'string=) "GLOB excludes non-matches"))))

(define-test db-get-system :parent offline
  (with-fresh-db (db)
    (load-sample db)
    (is string= "20240301-ddd" (getf (ls:get-system db "drakma") :latest)
        "lookup by system_name")
    (false (ls:get-system db "does-not-exist") "missing -> nil")))

(define-test db-trigger-update :parent offline
  (with-fresh-db (db)
    (load-sample db)
    (ls:upsert-system db '(:registry-name "cl-ppcre" :system-name "cl-ppcre"
                           :description "now mentions an html tokenizer too"
                           :latest "x" :deps "[]"))
    (true (member "cl-ppcre" (mapcar #'first (ls:search-fts db "tokenizer"))
                  :test #'string=)
          "UPDATE re-indexes FTS")))

(define-test db-trigger-delete :parent offline
  (with-fresh-db (db)
    (load-sample db)
    (sqlite:execute-non-query db "DELETE FROM system WHERE system_name = 'plump'")
    (false (member "plump" (mapcar #'first (ls:search-fts db "html")) :test #'string=)
           "DELETE removes from FTS")))
