package tests

import (
	"log"
	"os"
	"strings"
	"testing"
	"time"

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

func TestLineDbBasic(t *testing.T) {
	// Очищаем тестовую папку
	os.RemoveAll("./testdata")

	// Создаем опции инициализации
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 100,
		CacheTTL:  time.Minute,
		DBFolder:  "./testdata",
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName: "test",
				AllocSize:      256,
			},
		},
	}

	// Создаем базу данных
	db := linedb.NewLineDb(nil)
	defer db.Close()

	// Инициализируем базу данных
	if err := db.Init(false, initOptions); err != nil {
		t.Fatalf("Failed to init database: %v", err)
	}

	// Тест вставки
	testData := map[string]any{
		"name":  "test",
		"value": 123,
	}

	if err := db.Insert(testData, "test", linedb.LineDbAdapterOptions{}); err != nil {
		t.Fatalf("Failed to insert data: %v", err)
	}

	// Тест чтения
	allData, err := db.Read("test", linedb.LineDbAdapterOptions{})
	if err != nil {
		t.Fatalf("Failed to read data: %v", err)
	}

	if len(allData) != 1 {
		t.Fatalf("Expected 1 record, got %d", len(allData))
	}

	// Тест фильтрации
	filter := map[string]any{"name": "test"}
	filteredData, err := db.ReadByFilter(filter, "test", linedb.LineDbAdapterOptions{})
	if err != nil {
		t.Fatalf("Failed to filter data: %v", err)
	}

	if len(filteredData) != 1 {
		t.Fatalf("Expected 1 filtered record, got %d", len(filteredData))
	}

	// Тест обновления
	updateData := map[string]any{"value": 456}
	updateFilter := map[string]any{"name": "test"}
	updatedData, err := db.Update(updateData, "test", updateFilter, linedb.LineDbAdapterOptions{})
	if err != nil {
		t.Fatalf("Failed to update data: %v", err)
	}

	if len(updatedData) != 1 {
		t.Fatalf("Expected 1 updated record, got %d", len(updatedData))
	}

	// Тест удаления
	deleteFilter := map[string]any{"name": "test"}
	deletedData, err := db.Delete(deleteFilter, "test", linedb.LineDbAdapterOptions{})
	if err != nil {
		t.Fatalf("Failed to delete data: %v", err)
	}

	if len(deletedData) != 1 {
		t.Fatalf("Expected 1 deleted record, got %d", len(deletedData))
	}

	// Проверяем что данных больше нет
	remainingData, err := db.Read("test", linedb.LineDbAdapterOptions{})
	if err != nil {
		t.Fatalf("Failed to read remaining data: %v", err)
	}

	if len(remainingData) != 0 {
		t.Fatalf("Expected 0 remaining records, got %d", len(remainingData))
	}
}

func TestLineDbPartitioning(t *testing.T) {
	// Очищаем тестовую папку
	os.RemoveAll("./testdata")

	// Создаем опции инициализации с партиционированием
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 100,
		CacheTTL:  time.Minute,
		DBFolder:  "./testdata",
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName: "orders",
				AllocSize:      256,
			},
		},
		Partitions: []linedb.PartitionCollection{
			{
				CollectionName: "orders",
				PartIDFn: func(item any) string {
					if itemMap, ok := item.(map[string]any); ok {
						if userId, exists := itemMap["userId"]; exists {
							return toString(userId)
						}
					}
					return "default"
				},
			},
		},
	}

	// Создаем базу данных
	db := linedb.NewLineDb(nil)
	defer db.Close()

	// Инициализируем базу данных
	if err := db.Init(false, initOptions); err != nil {
		t.Fatalf("Failed to init database: %v", err)
	}

	// Создаем заказы для разных пользователей
	orders := []any{
		map[string]any{
			"userId": 1,
			"item":   "laptop",
			"price":  999.99,
		},
		map[string]any{
			"userId": 1,
			"item":   "mouse",
			"price":  29.99,
		},
		map[string]any{
			"userId": 2,
			"item":   "keyboard",
			"price":  89.99,
		},
	}

	// Вставляем заказы
	if err := db.Insert(orders, "orders", linedb.LineDbAdapterOptions{}); err != nil {
		t.Fatalf("Failed to insert orders: %v", err)
	}

	// Читаем все заказы
	allOrders, err := db.Read("orders", linedb.LineDbAdapterOptions{})
	if err != nil {
		t.Fatalf("Failed to read orders: %v", err)
	}

	if len(allOrders) != 3 {
		t.Fatalf("Expected 3 orders, got %d", len(allOrders))
	}

	// Фильтруем заказы пользователя 1
	user1Filter := map[string]any{"userId": 1}
	user1Orders, err := db.ReadByFilter(user1Filter, "orders", linedb.LineDbAdapterOptions{})
	if err != nil {
		t.Fatalf("Failed to filter user 1 orders: %v", err)
	}

	if len(user1Orders) != 2 {
		t.Fatalf("Expected 2 orders for user 1, got %d", len(user1Orders))
	}
}

// toString конвертирует значение в строку (для партиционирования)
func toString(value any) string {
	switch v := value.(type) {
	case string:
		return v
	case int:
		return string(rune(v))
	case int64:
		return string(rune(v))
	case float64:
		return string(rune(int(v)))
	default:
		return ""
	}
}

// setupUniqueCollection создаёт БД с коллекцией, у которой заданы UniqueFields
func setupUniqueCollection(t *testing.T, uniqueFields []string) (*linedb.LineDb, func()) {
	t.Helper()
	os.RemoveAll("./testdata")
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 100,
		CacheTTL:  time.Minute,
		DBFolder:  "./testdata",
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName: "users",
				AllocSize:      256,
				UniqueFields:   uniqueFields,
			},
		},
	}
	db := linedb.NewLineDb(nil)
	if err := db.Init(false, initOptions); err != nil {
		t.Fatalf("Failed to init database: %v", err)
	}
	return db, func() { db.Close(); os.RemoveAll("./testdata") }
}

// TestLineDbUniqueFieldsNonEmpty проверяет, что дубликаты непустых значений в уникальном поле запрещены
func TestLineDbUniqueFieldsNonEmpty(t *testing.T) {
	db, cleanup := setupUniqueCollection(t, []string{"email"})
	defer cleanup()

	opts := linedb.LineDbAdapterOptions{}

	if err := db.Insert(map[string]any{"name": "alice", "email": "alice@test.com"}, "users", opts); err != nil {
		t.Fatalf("Insert 1 failed: %v", err)
	}
	if err := db.Insert(map[string]any{"name": "bob", "email": "bob@test.com"}, "users", opts); err != nil {
		t.Fatalf("Insert 2 failed: %v", err)
	}

	// Дубликат email — ожидаем ошибку
	err := db.Insert(map[string]any{"name": "alice2", "email": "alice@test.com"}, "users", opts)
	if err == nil {
		t.Fatal("Expected unique constraint violation for duplicate email")
	}
	if err.Error() == "" {
		t.Fatalf("Expected meaningful error, got: %v", err)
	}

	all, _ := db.Read("users", opts)
	if len(all) != 2 {
		t.Fatalf("Expected 2 records, got %d", len(all))
	}
}

// TestLineDbUniqueFieldsEmptyValues проверяет, что пустые значения (nil, "") в уникальном поле допускают несколько записей
func TestLineDbUniqueFieldsEmptyValues(t *testing.T) {
	db, cleanup := setupUniqueCollection(t, []string{"email"})
	defer cleanup()

	opts := linedb.LineDbAdapterOptions{}

	// Несколько записей с отсутствующим полем email — должно быть разрешено
	if err := db.Insert(map[string]any{"name": "a"}, "users", opts); err != nil {
		t.Fatalf("Insert with nil email failed: %v", err)
	}
	if err := db.Insert(map[string]any{"name": "b"}, "users", opts); err != nil {
		t.Fatalf("Second insert with nil email failed: %v", err)
	}

	// Несколько записей с nil в email — должно быть разрешено
	if err := db.Insert(map[string]any{"name": "a", "email": nil}, "users", opts); err != nil {
		t.Fatalf("Insert with nil email failed: %v", err)
	}
	if err := db.Insert(map[string]any{"name": "b", "email": nil}, "users", opts); err != nil {
		t.Fatalf("Second insert with nil email failed: %v", err)
	}

	// Несколько записей с пустой строкой
	if err := db.Insert(map[string]any{"name": "c", "email": ""}, "users", opts); err != nil {
		t.Fatalf("Insert with empty email failed: %v", err)
	}
	if err := db.Insert(map[string]any{"name": "d", "email": ""}, "users", opts); err != nil {
		t.Fatalf("Second insert with empty email failed: %v", err)
	}

	all, err := db.Read("users", opts)
	if err != nil {
		t.Fatalf("Read failed: %v", err)
	}
	if len(all) != 6 {
		t.Fatalf("Expected 6 records (2 with nil email + 2 with empty string + 2 without email), got %d", len(all))
	}
}

// TestLineDbUniqueFieldsSkipCheckExistingForWrite проверяет режим SkipCheckExistingForWrite — уникальность не проверяется
func TestLineDbUniqueFieldsSkipCheckExistingForWrite(t *testing.T) {
	db, cleanup := setupUniqueCollection(t, []string{"email"})
	defer cleanup()

	opts := linedb.LineDbAdapterOptions{SkipCheckExistingForWrite: true}

	if err := db.Insert(map[string]any{"name": "a", "email": "same@test.com"}, "users", opts); err != nil {
		t.Fatalf("Insert 1 failed: %v", err)
	}
	// С тем же email, но с пропуском проверки — должно пройти
	if err := db.Insert(map[string]any{"name": "b", "email": "same@test.com"}, "users", opts); err != nil {
		t.Fatalf("Insert 2 with same email (skip check) failed: %v", err)
	}

	all, _ := db.Read("users", opts)
	if len(all) != 2 {
		t.Fatalf("Expected 2 records with SkipCheckExistingForWrite, got %d", len(all))
	}
}

// TestLineDbUniqueFieldsUpdateConflict проверяет, что Update не может установить значение, уже занятое другой записью
func TestLineDbUniqueFieldsUpdateConflict(t *testing.T) {
	db, cleanup := setupUniqueCollection(t, []string{"email"})
	defer cleanup()

	opts := linedb.LineDbAdapterOptions{}

	if err := db.Insert(map[string]any{"name": "alice", "email": "alice@test.com"}, "users", opts); err != nil {
		t.Fatalf("Insert alice failed: %v", err)
	}
	if err := db.Insert(map[string]any{"name": "bob", "email": "bob@test.com"}, "users", opts); err != nil {
		t.Fatalf("Insert bob failed: %v", err)
	}

	// Пытаемся обновить bob на email alice
	_, err := db.Update(
		map[string]any{"email": "alice@test.com"},
		"users",
		map[string]any{"name": "bob"},
		opts,
	)
	if err == nil {
		t.Fatal("Expected unique constraint violation when updating to existing email")
	}
}

// TestLineDbUniqueFieldsUpdateSameValue проверяет, что Update на ту же запись (тот же unique-значение) допустим
func TestLineDbUniqueFieldsUpdateSameValue(t *testing.T) {
	db, cleanup := setupUniqueCollection(t, []string{"email"})
	defer cleanup()

	opts := linedb.LineDbAdapterOptions{}

	if err := db.Insert(map[string]any{"name": "alice", "email": "alice@test.com"}, "users", opts); err != nil {
		t.Fatalf("Insert failed: %v", err)
	}

	// Обновляем имя, оставляя email тем же — допустимо
	updated, err := db.Update(
		map[string]any{"name": "alice_updated"},
		"users",
		map[string]any{"email": "alice@test.com"},
		opts,
	)
	if err != nil {
		t.Fatalf("Update same record failed: %v", err)
	}
	if len(updated) != 1 {
		t.Fatalf("Expected 1 updated record, got %d", len(updated))
	}
}

// TestLineDbUniqueFieldsMultipleFields проверяет несколько уникальных полей
func TestLineDbUniqueFieldsMultipleFields(t *testing.T) {
	db, cleanup := setupUniqueCollection(t, []string{"email", "username"})
	defer cleanup()

	opts := linedb.LineDbAdapterOptions{}

	if err := db.Insert(map[string]any{"name": "a", "email": "a@test.com", "username": "user_a"}, "users", opts); err != nil {
		t.Fatalf("Insert 1 failed: %v", err)
	}
	if err := db.Insert(map[string]any{"name": "b", "email": "b@test.com", "username": "user_b"}, "users", opts); err != nil {
		t.Fatalf("Insert 2 failed: %v", err)
	}

	// Дубликат email
	err := db.Insert(map[string]any{"name": "c", "email": "a@test.com", "username": "user_c"}, "users", opts)
	if err == nil {
		t.Fatal("Expected unique constraint violation for duplicate email")
	}

	// Дубликат username
	err = db.Insert(map[string]any{"name": "d", "email": "d@test.com", "username": "user_a"}, "users", opts)
	if err == nil {
		t.Fatal("Expected unique constraint violation for duplicate username")
	}

	all, _ := db.Read("users", opts)
	if len(all) != 2 {
		t.Fatalf("Expected 2 records, got %d", len(all))
	}
}

// TestLineDbUniqueFieldsBatchInsertDuplicate проверяет, что дубликат внутри одного batch Insert даёт ошибку
func TestLineDbUniqueFieldsBatchInsertDuplicate(t *testing.T) {
	db, cleanup := setupUniqueCollection(t, []string{"email"})
	defer cleanup()

	opts := linedb.LineDbAdapterOptions{}

	batch := []any{
		map[string]any{"name": "a", "email": "x@test.com"},
		map[string]any{"name": "b", "email": "x@test.com"},
	}
	err := db.Insert(batch, "users", opts)
	if err == nil {
		t.Fatal("Expected unique constraint violation in batch insert")
	}

	all, _ := db.Read("users", opts)
	if len(all) != 0 {
		t.Fatalf("Expected 0 records (batch should rollback or not persist), got %d", len(all))
	}
}

// TestLineDbUniqueFieldsUpdateToEmpty проверяет, что Update может установить пустое значение в unique-поле
func TestLineDbUniqueFieldsUpdateToEmpty(t *testing.T) {
	db, cleanup := setupUniqueCollection(t, []string{"email"})
	defer cleanup()

	opts := linedb.LineDbAdapterOptions{}

	if err := db.Insert(map[string]any{"name": "a", "email": "a@test.com"}, "users", opts); err != nil {
		t.Fatalf("Insert failed: %v", err)
	}
	if err := db.Insert(map[string]any{"name": "b", "email": "b@test.com"}, "users", opts); err != nil {
		t.Fatalf("Insert 2 failed: %v", err)
	}

	// Обновляем одну запись: email -> ""
	updated, err := db.Update(
		map[string]any{"email": ""},
		"users",
		map[string]any{"email": "a@test.com"},
		opts,
	)
	if err != nil {
		t.Fatalf("Update to empty email failed: %v", err)
	}
	if len(updated) != 1 {
		t.Fatalf("Expected 1 updated record, got %d", len(updated))
	}

	all, _ := db.Read("users", opts)
	if len(all) != 2 {
		t.Fatalf("Expected 2 records, got %d", len(all))
	}
}

// TestLineDbUniqueFieldsNoUniqueFields проверяет, что без UniqueFields дубликаты разрешены
func TestLineDbUniqueFieldsNoUniqueFields(t *testing.T) {
	db, cleanup := setupUniqueCollection(t, nil)
	defer cleanup()

	opts := linedb.LineDbAdapterOptions{}

	if err := db.Insert(map[string]any{"name": "a", "email": "dup@test.com"}, "users", opts); err != nil {
		t.Fatalf("Insert 1 failed: %v", err)
	}
	if err := db.Insert(map[string]any{"name": "b", "email": "dup@test.com"}, "users", opts); err != nil {
		t.Fatalf("Insert 2 (duplicate email, no unique) failed: %v", err)
	}

	all, _ := db.Read("users", opts)
	if len(all) != 2 {
		t.Fatalf("Expected 2 records when no unique fields, got %d", len(all))
	}
}

// TestLineDbEncode проверяет шифрование записей при Encode
func TestLineDbEncode(t *testing.T) {
	os.RemoveAll("./testdata")
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 100,
		CacheTTL:  time.Minute,
		DBFolder:  "./testdata",
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName: "secret",
				AllocSize:      512,
				Encode:         true,
				EncodeKey:      "test-secret-key",
			},
		},
	}
	db := linedb.NewLineDb(nil)
	if err := db.Init(false, initOptions); err != nil {
		t.Fatalf("Init failed: %v", err)
	}
	defer func() { db.Close(); os.RemoveAll("./testdata") }()

	opts := linedb.LineDbAdapterOptions{}
	if err := db.Insert(map[string]any{"name": "secret", "value": 42}, "secret", opts); err != nil {
		t.Fatalf("Insert failed: %v", err)
	}

	all, err := db.Read("secret", opts)
	if err != nil {
		t.Fatalf("Read failed: %v", err)
	}
	if len(all) != 1 {
		t.Fatalf("Expected 1 record, got %d", len(all))
	}
	r := all[0].(map[string]any)
	if r["name"] != "secret" || r["value"] != float64(42) {
		t.Fatalf("Expected name=secret value=42, got %+v", r)
	}
}

// TestLineDbAllocSizeOverflow проверяет ошибку при записи, превышающей allocSize-1
func TestLineDbAllocSizeOverflow(t *testing.T) {
	os.RemoveAll("./testdata")
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 100,
		CacheTTL:  time.Minute,
		DBFolder:  "./testdata",
		Collections: []linedb.JSONLFileOptions{
			{CollectionName: "tiny", AllocSize: 64},
		},
	}
	db := linedb.NewLineDb(nil)
	if err := db.Init(false, initOptions); err != nil {
		t.Fatalf("Init failed: %v", err)
	}
	defer func() { db.Close(); os.RemoveAll("./testdata") }()

	opts := linedb.LineDbAdapterOptions{}
	// Короткая запись — поместится (allocSize-1=63)
	if err := db.Insert(map[string]any{"x": "short"}, "tiny", opts); err != nil {
		t.Fatalf("Insert short failed: %v", err)
	}
	// Длинная — не поместится (JSON > 63 символов)
	longStr := strings.Repeat("a", 80)
	err := db.Insert(map[string]any{"x": longStr}, "tiny", opts)
	if err == nil {
		t.Fatal("Expected error for record exceeding allocSize-1")
	}
	if !strings.Contains(err.Error(), "exceeds") {
		t.Fatalf("Expected 'exceeds' in error, got: %v", err)
	}
}

// TestLineDbInitNormalizeExistingFile проверяет нормализацию при Init существующего файла
func TestLineDbInitNormalizeExistingFile(t *testing.T) {
	os.RemoveAll("./testdata")
	os.MkdirAll("./testdata", 0755)
	// Файл с записями разной длины
	content := `{"id":1,"a":"x"}
{"id":2,"a":"yy"}
{"id":3,"a":"zzz"}`
	if err := os.WriteFile("./testdata/norm.jsonl", []byte(content), 0644); err != nil {
		t.Fatalf("Write file: %v", err)
	}
	defer os.RemoveAll("./testdata")

	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 100,
		CacheTTL:  time.Minute,
		DBFolder:  "./testdata",
		Collections: []linedb.JSONLFileOptions{
			{CollectionName: "norm", AllocSize: 100},
		},
	}
	db := linedb.NewLineDb(nil)
	if err := db.Init(false, initOptions); err != nil {
		t.Fatalf("Init failed: %v", err)
	}
	defer db.Close()

	all, err := db.Read("norm", linedb.LineDbAdapterOptions{})
	if err != nil {
		t.Fatalf("Read failed: %v", err)
	}
	if len(all) != 3 {
		t.Fatalf("Expected 3 records, got %d", len(all))
	}
}

// setupCollectionWithFieldConstraints создаёт БД с FieldConstraints (required/unique)
func setupCollectionWithFieldConstraints(t *testing.T, constraints []linedb.FieldConstraint) (*linedb.LineDb, func()) {
	t.Helper()
	os.RemoveAll("./testdata")
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 100,
		CacheTTL:  time.Minute,
		DBFolder:  "./testdata",
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName:   "items",
				AllocSize:        256,
				FieldConstraints: constraints,
			},
		},
	}
	db := linedb.NewLineDb(nil)
	if err := db.Init(false, initOptions); err != nil {
		t.Fatalf("Failed to init database: %v", err)
	}
	return db, func() { db.Close(); os.RemoveAll("./testdata") }
}

// TestLineDbRequiredFieldsInsert проверяет, что required поля обязательны при Insert
func TestLineDbRequiredFieldsInsert(t *testing.T) {
	db, cleanup := setupCollectionWithFieldConstraints(t, []linedb.FieldConstraint{
		{Name: "email", Required: true},
		{Name: "name", Required: true},
	})
	defer cleanup()

	opts := linedb.LineDbAdapterOptions{}

	// Успех — оба поля заполнены
	if err := db.Insert(map[string]any{"name": "alice", "email": "a@test.com"}, "items", opts); err != nil {
		t.Fatalf("Insert with required fields failed: %v", err)
	}

	// Ошибка — отсутствует email (AbsentKey)
	err := db.Insert(map[string]any{"name": "bob"}, "items", opts)
	if err == nil {
		t.Fatal("Expected error for missing required field email")
	} else {
		log.Println("Error: ", err)
	}

	// Ошибка — email = nil
	err = db.Insert(map[string]any{"name": "bob", "email": nil}, "items", opts)
	if err == nil {
		t.Fatal("Expected error for nil required field email")
	} else {
		log.Println("Error: ", err)
	}

	// Ошибка — email = ""
	err = db.Insert(map[string]any{"name": "bob", "email": ""}, "items", opts)
	if err == nil {
		t.Fatal("Expected error for empty string in required field email")
	} else {
		log.Println("Error: ", err)
	}

	all, _ := db.Read("items", opts)
	if len(all) != 1 {
		t.Fatalf("Expected 1 record, got %d", len(all))
	}
}

// TestLineDbRequiredFieldsEmptyMode проверяет разные режимы интерпретации пустоты
func TestLineDbRequiredFieldsEmptyMode(t *testing.T) {
	// Режим: только отсутствие ключа — nil и "" допустимы
	db, cleanup := setupCollectionWithFieldConstraints(t, []linedb.FieldConstraint{
		{Name: "title", Required: true, EmptyMode: linedb.EmptyModeAbsentKey},
	})
	defer cleanup()

	opts := linedb.LineDbAdapterOptions{}

	// nil — допустимо (только AbsentKey проверяется)
	if err := db.Insert(map[string]any{"title": nil}, "items", opts); err != nil {
		t.Fatalf("Insert with nil (AbsentKey only) failed: %v", err)
	}
	// "" — допустимо
	if err := db.Insert(map[string]any{"title": ""}, "items", opts); err != nil {
		t.Fatalf("Insert with empty string (AbsentKey only) failed: %v", err)
	}
	// Отсутствие ключа — ошибка (поле не в записи)
	err := db.Insert(map[string]any{"other": "x"}, "items", opts)
	if err == nil {
		t.Fatal("Expected error for absent required key")
	}

	// Режим: только nil — AbsentKey и "" допустимы? Нет: AbsentKey при отсутствии — пусто.
	// При EmptyModeNil: пусто только когда v==nil. AbsentKey при отсутствии ключа: exists=false.
	// isEmptyByMode: if mode&EmptyModeAbsentKey && !exists return true. So if we use only EmptyModeNil,
	// AbsentKey is not in the mask, so we don't return true for !exists. Good.
	db2, cleanup2 := setupCollectionWithFieldConstraints(t, []linedb.FieldConstraint{
		{Name: "flag", Required: true, EmptyMode: linedb.EmptyModeNil},
	})
	defer cleanup2()

	// Ключ отсутствует — при EmptyModeNil мы не проверяем AbsentKey, так что !exists не даёт return true.
	// isEmptyByMode: проверяет mode&EmptyModeAbsentKey - если нет, то !exists не приводит к true.
	// Потом mode&EmptyModeNil && v==nil - но v при !exists будет нулевым при v, exists := m[key]. v = nil, exists = false.
	// Но мы заходим в v, exists := m[key]. Если !exists, v будет nil (zero value). So v==nil is true.
	// And mode&EmptyModeNil - if we have only Nil, we'd return true. So absent key would still be "empty" if we access v.
	// Actually no - we first check mode&EmptyModeAbsentKey && !exists - if that's not in mode, we skip.
	// Then mode&EmptyModeNil && v==nil - for absent key, v is nil. So we'd return true. So absent key + Nil mode would still fail.
	// The logic is: we return true (empty) if ANY of the conditions matching the mode are true. So:
	// - AbsentKey + !exists -> empty
	// - Nil + v==nil -> empty
	// - ZeroValue + ("" or 0) -> empty
	// For EmptyModeNil only: we don't check AbsentKey. We check Nil - and for absent key, v is nil (zero value from map lookup). So we'd return true. So absent key would still be empty. Good.
	// For EmptyModeZeroValue only: we'd only check ZeroValue. Absent key: v is nil, we don't have a case for nil in the switch (we'd fall through and return false). So absent key would NOT be empty. And nil would not be empty. Only "" and 0 would be.
	// Let me add a test for EmptyModeZeroValue: required field, value 0 should fail, value "" should fail, but absent key... would not fail? That might be surprising. Let me document it.
	if err := db2.Insert(map[string]any{"flag": false}, "items", opts); err != nil {
		t.Fatalf("Insert with false (bool, Nil mode) failed: %v", err)
	}
}

// TestLineDbRequiredFieldsUpdate проверяет, что Update не может установить пустое в required
func TestLineDbRequiredFieldsUpdate(t *testing.T) {
	db, cleanup := setupCollectionWithFieldConstraints(t, []linedb.FieldConstraint{
		{Name: "email", Required: true},
	})
	defer cleanup()

	opts := linedb.LineDbAdapterOptions{}

	if err := db.Insert(map[string]any{"name": "a", "email": "a@test.com"}, "items", opts); err != nil {
		t.Fatalf("Insert failed: %v", err)
	}

	// Ошибка — пытаемся установить email в ""
	_, err := db.Update(map[string]any{"email": ""}, "items", map[string]any{"email": "a@test.com"}, opts)
	if err == nil {
		t.Fatal("Expected error when setting required field to empty")
	}

	// Успех — обновляем другое поле
	_, err = db.Update(map[string]any{"name": "alice"}, "items", map[string]any{"email": "a@test.com"}, opts)
	if err != nil {
		t.Fatalf("Update non-required field failed: %v", err)
	}
}

// TestLineDbRequiredAndUniqueCombined проверяет комбинацию required и unique
func TestLineDbRequiredAndUniqueCombined(t *testing.T) {
	db, cleanup := setupCollectionWithFieldConstraints(t, []linedb.FieldConstraint{
		{Name: "email", Required: true, Unique: true},
	})
	defer cleanup()

	opts := linedb.LineDbAdapterOptions{}

	if err := db.Insert(map[string]any{"email": "x@test.com"}, "items", opts); err != nil {
		t.Fatalf("Insert failed: %v", err)
	}
	err := db.Insert(map[string]any{"email": "x@test.com"}, "items", opts)
	if err == nil {
		t.Fatal("Expected unique violation")
	}
	err = db.Insert(map[string]any{"email": ""}, "items", opts)
	if err == nil {
		t.Fatal("Expected required violation for empty email")
	}
}
