package persistence

import (
	"errors"
	"fmt"
	"testing"
)

func TestIsDeadlock(t *testing.T) {
	tests := []struct {
		name     string
		err      error
		expected bool
	}{
		{
			name:     "nil error",
			err:      nil,
			expected: false,
		},
		{
			name:     "deadlock error message",
			err:      errors.New("Deadlock found when trying to get lock"),
			expected: true,
		},
		{
			name:     "deadlock lowercase",
			err:      errors.New("deadlock detected"),
			expected: true,
		},
		{
			name:     "lock wait timeout",
			err:      errors.New("Lock wait timeout exceeded"),
			expected: true,
		},
		{
			name:     "lock wait timeout lowercase",
			err:      errors.New("lock wait timeout exceeded"),
			expected: true,
		},
		{
			name:     "error code 1213 (deadlock)",
			err:      errors.New("Error 1213: Deadlock found"),
			expected: true,
		},
		{
			name:     "error code 1205 (lock wait)",
			err:      errors.New("Error 1205: Lock wait timeout exceeded"),
			expected: true,
		},
		{
			name:     "wrapped deadlock error",
			err:      fmt.Errorf("transaction failed: %w", errors.New("deadlock detected")),
			expected: true,
		},
		{
			name:     "unrelated error",
			err:      errors.New("connection refused"),
			expected: false,
		},
		{
			name:     "syntax error",
			err:      errors.New("You have an error in your SQL syntax"),
			expected: false,
		},
		{
			name:     "empty error message",
			err:      errors.New(""),
			expected: false,
		},
		{
			name:     "partial match dead without lock",
			err:      errors.New("process is dead"),
			expected: false,
		},
		{
			name:     "contains 1213 as substring",
			err:      errors.New("request id 1213 failed"),
			expected: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := isDeadlock(tt.err)
			if got != tt.expected {
				t.Errorf("isDeadlock(%v) = %v, want %v", tt.err, got, tt.expected)
			}
		})
	}
}

func TestIsolationLevelConstants(t *testing.T) {
	// Verify the isolation level constants have the expected SQL values
	tests := []struct {
		name  string
		level IsolationLevel
		want  string
	}{
		{"ReadUncommitted", ReadUncommitted, "READ UNCOMMITTED"},
		{"ReadCommitted", ReadCommitted, "READ COMMITTED"},
		{"RepeatableRead", RepeatableRead, "REPEATABLE READ"},
		{"Serializable", Serializable, "SERIALIZABLE"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if string(tt.level) != tt.want {
				t.Errorf("IsolationLevel %s = %q, want %q", tt.name, tt.level, tt.want)
			}
		})
	}
}
