package query

import (
	"reflect"
	"testing"
)

func TestBuilderDeterministicSQL(t *testing.T) {
	const iterations = 100

	t.Run("BatchInsertColumns", func(t *testing.T) {
		// F1: batch INSERT column-list order
		records := []map[string]interface{}{
			{"a": "1", "m": "2", "z": "3"},
			{"b": "4", "n": "5"},
			{"z": "6", "a": "7"},
		}
		first := Insert("Account", nil).ValuesBatch(records).Build()
		for i := 0; i < iterations; i++ {
			got := Insert("Account", nil).ValuesBatch(records).Build()
			if got.SQL != first.SQL {
				t.Fatalf("iteration %d: SQL mismatch\nfirst=%s\ngot  =%s", i, first.SQL, got.SQL)
			}
			if !reflect.DeepEqual(got.Params, first.Params) {
				t.Fatalf("iteration %d: Params mismatch", i)
			}
		}
	})

	t.Run("BatchInsertOnDuplicateKeyUpdate", func(t *testing.T) {
		// F2: batch INSERT ON DUPLICATE KEY UPDATE clause order
		records := []map[string]interface{}{
			{"a": "1", "m": "2", "z": "3"},
			{"b": "4", "n": "5"},
		}
		updates := map[string]interface{}{"a": 1, "m": 2, "z": 3, "b": 4, "n": 5}
		first := Insert("Account", nil).ValuesBatch(records).OnDuplicateKeyUpdate(updates).Build()
		for i := 0; i < iterations; i++ {
			got := Insert("Account", nil).ValuesBatch(records).OnDuplicateKeyUpdate(updates).Build()
			if got.SQL != first.SQL {
				t.Fatalf("iteration %d: SQL mismatch\nfirst=%s\ngot  =%s", i, first.SQL, got.SQL)
			}
			if !reflect.DeepEqual(got.Params, first.Params) {
				t.Fatalf("iteration %d: Params mismatch", i)
			}
		}
	})

	t.Run("SingleRecordInsertColumns", func(t *testing.T) {
		// F3: single-record INSERT column / placeholder / param order
		data := map[string]interface{}{"a": 1, "m": 2, "z": 3, "b": 4, "n": 5}
		first := Insert("Account", data).Build()
		for i := 0; i < iterations; i++ {
			got := Insert("Account", data).Build()
			if got.SQL != first.SQL {
				t.Fatalf("iteration %d: SQL mismatch\nfirst=%s\ngot  =%s", i, first.SQL, got.SQL)
			}
			if !reflect.DeepEqual(got.Params, first.Params) {
				t.Fatalf("iteration %d: Params mismatch", i)
			}
		}
	})

	t.Run("SingleRecordInsertOnDuplicateKeyUpdate", func(t *testing.T) {
		// F4: single-record INSERT ON DUPLICATE KEY UPDATE clause order
		data := map[string]interface{}{"a": 1, "m": 2}
		updates := map[string]interface{}{"z": 3, "b": 4, "n": 5}
		first := Insert("Account", data).OnDuplicateKeyUpdate(updates).Build()
		for i := 0; i < iterations; i++ {
			got := Insert("Account", data).OnDuplicateKeyUpdate(updates).Build()
			if got.SQL != first.SQL {
				t.Fatalf("iteration %d: SQL mismatch\nfirst=%s\ngot  =%s", i, first.SQL, got.SQL)
			}
			if !reflect.DeepEqual(got.Params, first.Params) {
				t.Fatalf("iteration %d: Params mismatch", i)
			}
		}
	})

	t.Run("UpdateSet", func(t *testing.T) {
		// F5: UPDATE SET clause order
		data := map[string]interface{}{"a": 1, "m": 2, "z": 3, "b": 4, "n": 5}
		first := Update("Account").Set(data).WhereOp("Id", "=", "001xxx").Build()
		for i := 0; i < iterations; i++ {
			got := Update("Account").Set(data).WhereOp("Id", "=", "001xxx").Build()
			if got.SQL != first.SQL {
				t.Fatalf("iteration %d: SQL mismatch\nfirst=%s\ngot  =%s", i, first.SQL, got.SQL)
			}
			if !reflect.DeepEqual(got.Params, first.Params) {
				t.Fatalf("iteration %d: Params mismatch", i)
			}
		}
	})
}
