package utils

import (
	"testing"
)

type TestUser struct {
	Name     string `validate:"required,min=3,max=50"`
	Email    string `validate:"required,email"`
	Age      int    `validate:"gte=18,lte=100"`
	Phone    string `validate:"phone"`
	Username string `validate:"required,alphanum,min=4"`
}

func TestValidateStructDetailed(t *testing.T) {
	tests := []struct {
		name     string
		user     TestUser
		wantErr  bool
		errCount int
	}{
		{
			name: "valid user",
			user: TestUser{
				Name:     "John Doe",
				Email:    "john@example.com",
				Age:      25,
				Phone:    "08123456789",
				Username: "johndoe",
			},
			wantErr:  false,
			errCount: 0,
		},
		{
			name: "invalid user - multiple errors",
			user: TestUser{
				Name:     "Jo", // too short
				Email:    "invalid-email",
				Age:      15,    // too young
				Phone:    "123", // invalid phone
				Username: "jo",  // too short
			},
			wantErr:  true,
			errCount: 5,
		},
		{
			name:     "empty user",
			user:     TestUser{},
			wantErr:  true,
			errCount: 4, // Name, Email, Username required; Age will be 0 which is < 18
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := ValidateStructDetailed(tt.user)

			if result.IsValid == tt.wantErr {
				t.Errorf("ValidateStructDetailed() IsValid = %v, want %v", result.IsValid, !tt.wantErr)
			}

			if result.Count != tt.errCount {
				t.Errorf("ValidateStructDetailed() error count = %v, want %v", result.Count, tt.errCount)
			}

			// Check if error messages are user-friendly
			for field, err := range result.Errors {
				if err.Message == "" {
					t.Errorf("Empty error message for field %s", field)
				}
				if err.Field == "" {
					t.Errorf("Empty field name for field %s", field)
				}
			}
		})
	}
}

func TestGetFieldName(t *testing.T) {
	tests := []struct {
		input    string
		expected string
	}{
		{"Name", "Name"},
		{"FirstName", "First Name"},
		{"EmailAddress", "Email Address"},
		{"PhoneNumber", "Phone Number"},
	}

	for _, tt := range tests {
		t.Run(tt.input, func(t *testing.T) {
			result := getFieldName(tt.input)
			if result != tt.expected {
				t.Errorf("getFieldName(%s) = %s, want %s", tt.input, result, tt.expected)
			}
		})
	}
}

func TestCustomValidations(t *testing.T) {
	tests := []struct {
		name  string
		value string
		tag   string
		valid bool
	}{
		{"valid phone", "08123456789", "phone", true},
		{"valid phone with +", "+628123456789", "phone", true},
		{"invalid phone - too short", "123", "phone", false},
		{"valid NIK", "1234567890123456", "nik", true},
		{"invalid NIK - too short", "123456789", "nik", false},
		{"invalid NIK - contains letters", "123456789012345a", "nik", false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidateField(tt.value, tt.tag)
			isValid := err == nil

			if isValid != tt.valid {
				t.Errorf("ValidateField(%s, %s) valid = %v, want %v", tt.value, tt.tag, isValid, tt.valid)
			}
		})
	}
}

func BenchmarkValidateStruct(b *testing.B) {
	user := TestUser{
		Name:     "John Doe",
		Email:    "john@example.com",
		Age:      25,
		Phone:    "08123456789",
		Username: "johndoe",
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		ValidateStructDetailed(user)
	}
}
