;; Phase 2 — query AST + boolean/phrase evaluation (hand-built Query values).
;; Corpus:
;;   doc 1 "the quick brown dog"   -> the quick brown dog
;;   doc 2 "a quick brown fox"     -> a quick brown fox
;;   doc 3 "the dog barks loudly"  -> the dog barks loudly
;; All queries run in ONE program evaluation (search-batch) to stay fast.

(define
  search-corpus
  "idx = indexDoc 3 \"the dog barks loudly\" (indexDoc 2 \"a quick brown fox\" (indexDoc 1 \"the quick brown dog\" emptyIndex))\n")

(define
  bool-cases
  (list
    (list
      "term in two docs"
      "evalQuery idx (Term \"quick\")"
      (list 1 2))
    (list
      "term in two docs (the)"
      "evalQuery idx (Term \"the\")"
      (list 1 3))
    (list "term in one doc" "evalQuery idx (Term \"fox\")" (list 2))
    (list "term absent" "evalQuery idx (Term \"zzz\")" (list))
    (list
      "term case-sensitive at AST level"
      "evalQuery idx (Term \"QUICK\")"
      (list))
    (list "term on empty index" "evalQuery emptyIndex (Term \"cat\")" (list))
    (list
      "and both terms"
      "evalQuery idx (And (Term \"quick\") (Term \"brown\"))"
      (list 1 2))
    (list
      "and overlap subset"
      "evalQuery idx (And (Term \"the\") (Term \"dog\"))"
      (list 1 3))
    (list
      "and disjoint is empty"
      "evalQuery idx (And (Term \"the\") (Term \"fox\"))"
      (list))
    (list
      "and right-nested"
      "evalQuery idx (And (Term \"the\") (And (Term \"dog\") (Term \"barks\")))"
      (list 3))
    (list
      "or two singletons"
      "evalQuery idx (Or (Term \"fox\") (Term \"barks\"))"
      (list 2 3))
    (list
      "or all docs"
      "evalQuery idx (Or (Term \"quick\") (Term \"the\"))"
      (list 1 2 3))
    (list
      "or with absent term"
      "evalQuery idx (Or (Term \"fox\") (Term \"zzz\"))"
      (list 2))
    (list "not term" "evalQuery idx (Not (Term \"the\"))" (list 2))
    (list "not term 2" "evalQuery idx (Not (Term \"quick\"))" (list 3))
    (list
      "and with not"
      "evalQuery idx (And (Term \"quick\") (Not (Term \"the\")))"
      (list 2))
    (list
      "double negation"
      "evalQuery idx (Not (Not (Term \"fox\")))"
      (list 2))
    (list
      "or of and with term"
      "evalQuery idx (Or (And (Term \"the\") (Term \"dog\")) (Term \"fox\"))"
      (list 1 2 3))
    (list
      "phrase adjacent both docs"
      "evalQuery idx (Phrase [\"quick\", \"brown\"])"
      (list 1 2))
    (list
      "phrase adjacent one doc"
      "evalQuery idx (Phrase [\"brown\", \"dog\"])"
      (list 1))
    (list
      "phrase the quick"
      "evalQuery idx (Phrase [\"the\", \"quick\"])"
      (list 1))
    (list
      "phrase dog barks"
      "evalQuery idx (Phrase [\"dog\", \"barks\"])"
      (list 3))
    (list
      "phrase non-adjacent empty"
      "evalQuery idx (Phrase [\"quick\", \"dog\"])"
      (list))
    (list
      "phrase order matters"
      "evalQuery idx (Phrase [\"brown\", \"quick\"])"
      (list))
    (list
      "phrase single term"
      "evalQuery idx (Phrase [\"dog\"])"
      (list 1 3))
    (list
      "phrase three terms"
      "evalQuery idx (Phrase [\"the\", \"dog\", \"barks\"])"
      (list 3))
    (list
      "and of phrase and term"
      "evalQuery idx (And (Phrase [\"quick\", \"brown\"]) (Term \"dog\"))"
      (list 1))
    (list
      "not of phrase"
      "evalQuery idx (Not (Phrase [\"quick\", \"brown\"]))"
      (list 3))))

(define
  bool-results
  (search-batch search-corpus (map (fn (c) (nth c 1)) bool-cases)))

(map-indexed
  (fn
    (i c)
    (hk-test (nth c 0) (nth bool-results i) (nth c 2)))
  bool-cases)

{:fail hk-test-fail :pass hk-test-pass :fails hk-test-fails}
