package db

import (
	"strings"
	"testing"

	"GoNavi-Wails/internal/connection"
)

func TestGenerateChangePreview_Inserts(t *testing.T) {
	changes := connection.ChangeSet{
		Inserts: []map[string]interface{}{
			{"name": "alice", "age": float64(30)},
			{"name": "bob", "age": nil},
		},
	}
	deletes, updates, inserts := GenerateChangePreview("users", changes, mysqlQuote)
	if len(inserts) != 2 {
		t.Fatalf("expected 2 inserts, got %d", len(inserts))
	}
	expected1 := "INSERT INTO `users` (`age`, `name`) VALUES (30, 'alice');"
	expected2 := "INSERT INTO `users` (`name`) VALUES ('bob');"
	if inserts[0] != expected1 {
		t.Errorf("insert[0]: got  %s\nwant %s", inserts[0], expected1)
	}
	if inserts[1] != expected2 {
		t.Errorf("insert[1]: got  %s\nwant %s", inserts[1], expected2)
	}
	if len(deletes) != 0 || len(updates) != 0 {
		t.Errorf("expected empty deletes/updates")
	}
}

func TestGenerateChangePreview_Deletes(t *testing.T) {
	changes := connection.ChangeSet{
		Deletes: []map[string]interface{}{
			{"id": float64(1), "name": "alice"},
			{"id": float64(2)},
		},
	}
	deletes, updates, inserts := GenerateChangePreview("users", changes, mysqlQuote)
	if len(deletes) != 2 {
		t.Fatalf("expected 2 deletes, got %d", len(deletes))
	}
	expected1 := "DELETE FROM `users` WHERE `id` = 1 AND `name` = 'alice';"
	if deletes[0] != expected1 {
		t.Errorf("delete[0]: got  %s\nwant %s", deletes[0], expected1)
	}
	if len(updates) != 0 || len(inserts) != 0 {
		t.Errorf("expected empty updates/inserts")
	}
}

func TestGenerateChangePreview_Updates(t *testing.T) {
	changes := connection.ChangeSet{
		Updates: []connection.UpdateRow{
			{
				Keys:   map[string]interface{}{"id": float64(1)},
				Values: map[string]interface{}{"name": "charlie", "age": float64(25)},
			},
		},
	}
	deletes, updates, inserts := GenerateChangePreview("users", changes, mysqlQuote)
	if len(updates) != 1 {
		t.Fatalf("expected 1 update, got %d", len(updates))
	}
	// SET clause column order is map-iteration-based, so check substring presence
	if !strings.Contains(updates[0], "UPDATE `users` SET") {
		t.Errorf("update: missing UPDATE clause: %s", updates[0])
	}
	if !strings.Contains(updates[0], "WHERE `id` = 1") {
		t.Errorf("update: missing WHERE clause: %s", updates[0])
	}
	if !strings.Contains(updates[0], "`name` = 'charlie'") {
		t.Errorf("update: missing name set: %s", updates[0])
	}
	if !strings.Contains(updates[0], "`age` = 25") {
		t.Errorf("update: missing age set: %s", updates[0])
	}
	if len(deletes) != 0 || len(inserts) != 0 {
		t.Errorf("expected empty deletes/inserts")
	}
}

func TestGenerateChangePreview_EmptyChanges(t *testing.T) {
	deletes, updates, inserts := GenerateChangePreview("t", connection.ChangeSet{}, mysqlQuote)
	if len(deletes) != 0 || len(updates) != 0 || len(inserts) != 0 {
		t.Error("expected all empty for empty changeset")
	}
}

func TestFormatLiteral(t *testing.T) {
	cases := []struct {
		val      interface{}
		expected string
	}{
		{nil, "NULL"},
		{"hello", "'hello'"},
		{"it's a test", "'it\\'s a test'"},
		{float64(42), "42"},
		{int64(-1), "-1"},
		{true, "TRUE"},
		{false, "FALSE"},
	}
	for _, c := range cases {
		got := formatLiteral(c.val)
		if got != c.expected {
			t.Errorf("formatLiteral(%v): got %s, want %s", c.val, got, c.expected)
		}
	}
}

func mysqlQuote(s string) string { return "`" + s + "`" }
