// Тесты для дебага точечного Update через индекс.
// Случай 1: изменение поля, не входящего в индекс (поиск по email, обновляем name).
// Случай 2: изменение поля, входящего в индекс (поиск по email, обновляем email).
package tests

import (
	"os"
	"testing"
	"time"

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

func setupPointUpdateDB(t *testing.T) (*linedb.LineDb, func()) {
	t.Helper()
	dir := "./data/test-point-update"
	os.RemoveAll(dir)
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 100,
		CacheTTL:  time.Minute,
		DBFolder:  dir,
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName: "users",
				AllocSize:      256,
				IndexedFields:  []string{"id", "email", "name"},
			},
		},
	}
	db := linedb.NewLineDb(nil)
	if err := db.Init(false, initOptions); err != nil {
		t.Fatalf("Init failed: %v", err)
	}
	return db, func() { db.Close(); os.RemoveAll(dir) }
}

// TestPointUpdate_NonIndexedField: поиск по email (индекс), обновление name (не индекс).
func TestPointUpdate_NonIndexedField(t *testing.T) {
	// db, cleanup := setupPointUpdateDB(t)
	db, _ := setupPointUpdateDB(t)
	// defer cleanup()
	opts := linedb.LineDbAdapterOptions{}

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

	// Поиск по email (индекс), обновляем name (не индекс)
	updated, err := db.Update(
		map[string]any{"name": "Bobina"},
		"users",
		map[string]any{"email": "bob@test.com"},
		opts,
	)
	if err != nil {
		t.Fatalf("Update failed: %v", err)
	}
	if len(updated) != 1 {
		t.Fatalf("Expected 1 updated record, got %d", len(updated))
	}
	m := updated[0].(map[string]any)
	if m["name"] != "Bobina" || m["email"] != "bob@test.com" {
		t.Errorf("Expected name=Bobina email=bob@test.com, got name=%v email=%v", m["name"], m["email"])
	}

	// Проверяем ReadByFilter по старому email — должен найти обновлённую запись
	found, err := db.ReadByFilter(map[string]any{"email": "bob@test.com"}, "users", opts)
	if err != nil {
		t.Fatalf("ReadByFilter failed: %v", err)
	}
	if len(found) != 1 {
		t.Fatalf("Expected 1 record by email bob@test.com, got %d", len(found))
	}
	if m2 := found[0].(map[string]any); m2["name"] != "Bobina" {
		t.Errorf("Expected name=bob_renamed, got %v", m2["name"])
	}
}

// TestPointUpdate_IndexedField: поиск по email (индекс), обновление email.
func TestPointUpdate_IndexedField(t *testing.T) {
	db, cleanup := setupPointUpdateDB(t)
	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, обновляем тот же email
	updated, err := db.Update(
		map[string]any{"email": "bob_new@test.com"},
		"users",
		map[string]any{"email": "bob@test.com"},
		opts,
	)
	if err != nil {
		t.Fatalf("Update failed: %v", err)
	}
	if len(updated) != 1 {
		t.Fatalf("Expected 1 updated record, got %d", len(updated))
	}
	m := updated[0].(map[string]any)
	if m["email"] != "bob_new@test.com" || m["name"] != "bob" {
		t.Errorf("Expected email=bob_new@test.com name=bob, got email=%v name=%v", m["email"], m["name"])
	}

	// По старому email записей быть не должно
	foundOld, err := db.ReadByFilter(map[string]any{"email": "bob@test.com"}, "users", opts)
	if err != nil {
		t.Fatalf("ReadByFilter old failed: %v", err)
	}
	if len(foundOld) != 0 {
		t.Errorf("Expected 0 records for old email bob@test.com, got %d", len(foundOld))
	}

	// По новому email — одна запись
	foundNew, err := db.ReadByFilter(map[string]any{"email": "bob_new@test.com"}, "users", opts)
	if err != nil {
		t.Fatalf("ReadByFilter new failed: %v", err)
	}
	if len(foundNew) != 1 {
		t.Fatalf("Expected 1 record for new email bob_new@test.com, got %d", len(foundNew))
	}
	if m2 := foundNew[0].(map[string]any); m2["name"] != "bob" {
		t.Errorf("Expected name=bob, got %v", m2["name"])
	}
}
