//go:build !vectors

package memorysearch

import (
	"testing"

	"github.com/blevesearch/bleve/v2"
	"github.com/blevesearch/bleve/v2/analysis/lang/cjk"
	"github.com/blevesearch/bleve/v2/mapping"
	"github.com/blevesearch/bleve/v2/registry"
	index "github.com/blevesearch/bleve_index_api"
)

// TestBleveDependencyContract locks the pieces of the Bleve dependency that
// the local Memory search index relies on at the default build tag
// (!vectors). It deliberately constructs real Bleve objects instead of
// grepping go.mod so that a future dependency downgrade or analyzer swap
// cannot silently regress the search quality.
//
// The companion file vectors_forbidden.go is gated by the `vectors` build
// tag and fails at compile time. Together the two files guarantee that this
// package is never built, tested, or shipped with the Bleve vectors API
// enabled, which would pull in go-faiss CGO dependencies.
func TestBleveDependencyContract(t *testing.T) {
	t.Parallel()

	t.Run("bleve exposes BM25 scoring model constant", func(t *testing.T) {
		t.Parallel()
		if index.BM25Scoring != "bm25" {
			t.Fatalf("expected index.BM25Scoring to be the string %q, got %q",
				"bm25", index.BM25Scoring)
		}
		if _, ok := index.SupportedScoringModels[index.BM25Scoring]; !ok {
			t.Fatalf("BM25 scoring model is not in index.SupportedScoringModels")
		}
	})

	t.Run("index mapping accepts BM25 scoring model and builds", func(t *testing.T) {
		t.Parallel()
		m := mapping.NewIndexMapping()
		m.ScoringModel = index.BM25Scoring
		// Exercise the full bleve.New path (in-memory scorch) so the
		// mapping is validated by bleve itself rather than only by our
		// own field assignment. Index one trivial document so the BM25
		// scorer is wired through the analysis + indexing pipeline.
		idx, err := bleve.NewMemOnly(m)
		if err != nil {
			t.Fatalf("bleve.NewMemOnly with BM25 mapping failed: %v", err)
		}
		defer idx.Close()
		if err := idx.Index("doc1", map[string]string{"body": "迁移 重号 测试"}); err != nil {
			t.Fatalf("bleve.Index with BM25 mapping failed: %v", err)
		}
	})

	t.Run("CJK analyzer can be registered and tokenizes sample", func(t *testing.T) {
		t.Parallel()
		cache := registry.NewCache()
		if _, err := cache.DefineAnalyzer(cjk.AnalyzerName, map[string]interface{}{
			"type": cjk.AnalyzerName,
		}); err != nil {
			t.Fatalf("register cjk analyzer: %v", err)
		}
		analyzer, err := cache.AnalyzerNamed(cjk.AnalyzerName)
		if err != nil || analyzer == nil {
			t.Fatalf("cjk analyzer not resolvable after registration: %v", err)
		}
		tokens := analyzer.Analyze([]byte("迁移 重号 测试"))
		if len(tokens) == 0 {
			t.Fatalf("cjk analyzer produced zero tokens for CJK sample")
		}
	})
}
