package db

import (
	"testing"
)

func TestEngineBasic(t *testing.T) {
	dir := t.TempDir()
	e, err := NewEngine(dir)
	if err != nil {
		t.Fatalf("Failed to create engine: %v", err)
	}
	defer e.Close()

	e.Set("node1.ip", "192.168.1.1", 100)
	e.Set("node2.ip", "192.168.1.2", 101)

	val, ok := e.Get("node1.ip")
	if !ok || val != "192.168.1.1" {
		t.Errorf("Expected 192.168.1.1, got %v", val)
	}

	val, ok = e.Get("node2.ip")
	if !ok || val != "192.168.1.2" {
		t.Errorf("Expected 192.168.1.2, got %v", val)
	}
}

func TestEngineQuery(t *testing.T) {
	dir := t.TempDir()
	e, err := NewEngine(dir)
	if err != nil {
		t.Fatalf("Failed to create engine: %v", err)
	}
	defer e.Close()

	// Seed data
	e.Set("prod.node1.config", "ver=1.0", 10)
	e.Set("prod.node2.config", "ver=1.0", 11)
	e.Set("dev.node1.config", "ver=2.0-beta", 12)
	e.Set("test.node1.config", "ver=1.0", 13)
	e.Set("prod.db.config", "host=localhost", 14)

	tests := []struct {
		sql      string
		expected int
	}{
		{`key like "prod.*"`, 3},
		{`key like "prod.*" and value = "ver=1.0"`, 2},
		{`value = "ver=1.0"`, 3},
		{`CommitIndex > 11`, 3}, // 12, 13, 14
		{`CommitIndex >= 11`, 4}, // 11, 12, 13, 14
		{`CommitIndex < 12`, 2}, // 10, 11
		{`key like "*.config"`, 5},
		{`key = "prod.node1.config"`, 1},
		{`key like "prod.*" and CommitIndex > 10`, 2}, // node2(11), db(14)
	}

	for i, tt := range tests {
		res, err := e.Query(tt.sql)
		if err != nil {
			t.Errorf("Test %d: Query failed: %v", i, err)
			continue
		}
		if len(res) != tt.expected {
			t.Errorf("Test %d: Query '%s' expected %d results, got %d. Results: %+v", i, tt.sql, tt.expected, len(res), res)
		}
	}
}

func TestSnapshotRestore(t *testing.T) {
	dir := t.TempDir()
	e, err := NewEngine(dir)
	if err != nil {
		t.Fatalf("Failed to create engine: %v", err)
	}
	// No defer close here, we want to simulate restart
	
	e.Set("k1", "v1", 1)
	e.Set("k2", "v2", 2)

	data, err := e.Snapshot()
	if err != nil {
		t.Fatalf("Snapshot failed: %v", err)
	}
	e.Close()

	// Create new engine pointing to same dir (simulating restart/restore)
	e2, err := NewEngine(dir)
	if err != nil {
		t.Fatalf("Failed to open engine: %v", err)
	}
	defer e2.Close()
	
	if err := e2.Restore(data); err != nil {
		t.Fatalf("Restore failed: %v", err)
	}

	val, ok := e2.Get("k1")
	if !ok || val != "v1" {
		t.Errorf("Restored k1 wrong: %v", val)
	}
	
	val, ok = e2.Get("k2")
	if !ok || val != "v2" {
		t.Errorf("Restored k2 wrong: %v", val)
	}
}

func TestWildcardMatch(t *testing.T) {
	tests := []struct {
		str, pat string
		match    bool
	}{
		{"abc", "abc", true},
		{"abc", "a*", true},
		{"abc", "*c", true},
		{"abc", "a*c", true},
		{"abc", "ab?", true},
		{"abc", "abd", false},
		{"prod.node1.config", "prod.*", true},
	}

	for _, tt := range tests {
		if got := WildcardMatch(tt.str, tt.pat); got != tt.match {
			t.Errorf("Match(%q, %q) = %v; want %v", tt.str, tt.pat, got, tt.match)
		}
	}
}

