package validate

import (
	"fmt"
	"testing"

	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// Test struct for validation scenarios
type User struct {
	Username string `json:"username" validate:"required,min=4"`
	Email    string `json:"email" validate:"required,email"`
	Bio      string `json:"bio" validate:"is-awesome"`
}

// Custom validation function: must be "awesome"
func IsAwesomeValidator(fl validator.FieldLevel) bool {
	return fl.Field().String() == "awesome"
}

func TestValidateAll_Success(t *testing.T) {
	// A custom option for the "is-awesome" tag
	awesomeOption := Option{
		ValidatorName: "is-awesome",
		ValidatorFunc: IsAwesomeValidator,
	}

	v, err := NewWithDefaultEN(awesomeOption)
	require.NoError(t, err)

	user := User{
		Username: "tester",
		Email:    "test@example.com",
		Bio:      "awesome",
	}

	err = v.ValidateAll(user)
	assert.NoError(t, err)
}

func TestValidateAll_DefaultTranslationFailure(t *testing.T) {
	v, err := NewWithDefaultEN()
	require.NoError(t, err)

	user := struct {
		Name  string `json:"name" validate:"required"`
		Email string `json:"email_address" validate:"email"`
	}{
		Name:  "",
		Email: "not-an-email",
	}

	err = v.ValidateAll(user)
	require.Error(t, err)

	var validationErrs ValidationErrors
	require.ErrorAs(t, err, &validationErrs)
	require.Len(t, validationErrs, 2)

	// Check errors (order might vary)
	errMap := make(map[string]string)
	for _, ve := range validationErrs {
		errMap[ve.Field] = ve.Message
	}

	assert.Equal(t, "name is a required field", errMap["name"])
	assert.Equal(t, "email_address must be a valid email address", errMap["email_address"])
}

func TestValidateAll_CustomValidationWithTranslation(t *testing.T) {
	// A custom option for a "status" validator with translation
	statusOption := Option{
		ValidatorName: "status",
		ValidatorFunc: func(fl validator.FieldLevel) bool {
			status := fl.Field().String()
			return status == "active" || status == "inactive"
		},
		// Function to register the translation
		RegisterTranslationFunc: func(ut ut.Translator) error {
			return ut.Add("status", "{0} must be 'active' or 'inactive'", true)
		},
		// Function that defines how the translation message is generated
		TranslationFunc: func(ut ut.Translator, fe validator.FieldError) string {
			t, _ := ut.T("status", fe.Field())
			return t
		},
	}

	v, err := NewWithDefaultEN(statusOption)
	require.NoError(t, err)

	payload := struct {
		Status string `json:"user_status" validate:"status"`
	}{
		Status: "pending",
	}

	err = v.ValidateAll(payload)
	require.Error(t, err)

	var validationErrs ValidationErrors
	require.ErrorAs(t, err, &validationErrs)
	require.Len(t, validationErrs, 1)

	assert.Equal(t, "user_status", validationErrs[0].Field)
	assert.Equal(t, "user_status must be 'active' or 'inactive'", validationErrs[0].Message)
	fmt.Println(validationErrs.Error()) // For visual confirmation
}
