package nonpartitioned

import (
	"errors"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"direct-dev.ru/gitea/GiteaAdmin/elowdb-go/pkg/linedb"
)

// failingLookupStore — IndexStore, у которого Lookup всегда возвращает ошибку (для проверки FailOnFailureIndexRead).
type failingLookupStore struct {
	inner linedb.IndexStore
}

func (f *failingLookupStore) Lookup(collection, field, value string) ([]linedb.IndexPosition, error) {
	return nil, errors.New("simulated index lookup failure")
}

func (f *failingLookupStore) IndexRecord(collection, partition string, fields []string, record map[string]any, lineIndex int) {
	f.inner.IndexRecord(collection, partition, fields, record, lineIndex)
}

func (f *failingLookupStore) UnindexRecord(collection, partition string, fields []string, record map[string]any, lineIndex int) {
	f.inner.UnindexRecord(collection, partition, fields, record, lineIndex)
}

func (f *failingLookupStore) Rebuild(collection, partition string, fields []string, records []any, lineIndexes []int) error {
	return f.inner.Rebuild(collection, partition, fields, records, lineIndexes)
}

func (f *failingLookupStore) Clear(collection string) error {
	return f.inner.Clear(collection)
}

func TestReadByFilter_FailOnFailureIndexRead_ReturnsError(t *testing.T) {
	dir := filepath.Join(dbDir, "index_fail")
	_ = os.RemoveAll(dir)
	if err := os.MkdirAll(dir, 0755); err != nil {
		t.Fatalf("mkdir: %v", err)
	}

	initOptions := &linedb.LineDbInitOptions{
		DBFolder: dir,
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName: "users",
				AllocSize:      512,
				IndexedFields:  []string{"id", "email"},
			},
		},
	}

	inner := linedb.NewInMemoryIndexStore()
	store := &failingLookupStore{inner: inner}

	db := linedb.NewLineDb(&linedb.LineDbOptions{IndexStore: store})
	if err := db.Init(true, initOptions); err != nil {
		t.Fatalf("Init: %v", err)
	}
	defer db.Close()

	if err := db.Insert(map[string]any{"id": 1, "email": "x@test.com"}, "users", linedb.LineDbAdapterOptions{}); err != nil {
		t.Fatalf("Insert: %v", err)
	}

	// Без опции — ошибка индекса игнорируется, полный перебор находит запись
	found, err := db.ReadByFilter(map[string]any{"email": "x@test.com"}, "users", linedb.LineDbAdapterOptions{})
	if err != nil {
		t.Fatalf("ReadByFilter without flag: %v", err)
	}
	if len(found) != 1 {
		t.Fatalf("expected 1 via fallback, got %d", len(found))
	}

	// С FailOnFailureIndexRead — возвращается ошибка индекса
	_, err = db.ReadByFilter(map[string]any{"email": "x@test.com"}, "users", linedb.LineDbAdapterOptions{
		FailOnFailureIndexRead: true,
	})
	if err == nil {
		t.Fatal("expected error when FailOnFailureIndexRead and index Lookup fails")
	}
	if !strings.Contains(err.Error(), "index read failed") || !strings.Contains(err.Error(), "simulated index lookup failure") {
		t.Fatalf("unexpected error: %v", err)
	}
}
