package validation

import (
	"dance-lessons-coach/pkg/config"
	"errors"
	"fmt"
	"reflect"
	"strings"

	"github.com/go-playground/locales/en"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	en_translations "github.com/go-playground/validator/v10/translations/en"
)

// Validator wraps the go-playground/validator with custom error handling
type Validator struct {
	validate   *validator.Validate
	translator ut.Translator
}

// NewValidator creates a new validator instance with custom error handling
func NewValidator() (*Validator, error) {
	// Create validator instance
	validate := validator.New()

	// Register translations
	english := en.New()
	uni := ut.New(english, english)
	trans, _ := uni.GetTranslator("en")

	// Register translation for default validator
	if err := en_translations.RegisterDefaultTranslations(validate, trans); err != nil {
		return nil, fmt.Errorf("failed to register translations: %w", err)
	}

	// Register custom validations
	if err := registerCustomValidations(validate); err != nil {
		return nil, fmt.Errorf("failed to register custom validations: %w", err)
	}

	return &Validator{
		validate:   validate,
		translator: trans,
	}, nil
}

// Validate validates a struct and returns validation errors
func (v *Validator) Validate(structObj interface{}) error {
	if structObj == nil {
		return errors.New("validation: nil object provided")
	}

	// Get the type of the struct
	structType := reflect.TypeOf(structObj)
	if structType.Kind() != reflect.Struct {
		return fmt.Errorf("validation: expected struct, got %s", structType.Kind())
	}

	// Perform validation
	if err := v.validate.Struct(structObj); err != nil {
		if _, ok := err.(*validator.InvalidValidationError); ok {
			return fmt.Errorf("validation: invalid validation error: %w", err)
		}

		// Convert validation errors to custom format
		validationErrors := err.(validator.ValidationErrors)
		return v.formatValidationErrors(validationErrors)
	}

	return nil
}

// formatValidationErrors converts validator.ValidationErrors to a custom error type
func (v *Validator) formatValidationErrors(errors validator.ValidationErrors) error {
	var errorMessages []string

	for _, err := range errors {
		field := err.Field()
		tag := err.Tag()
		param := err.Param()

		// Get custom error message
		message := fmt.Errorf("%s failed validation for '%s'", field, tag).Error()

		// Add parameter if available
		if param != "" {
			message += fmt.Sprintf(" (parameter: %s)", param)
		}

		errorMessages = append(errorMessages, message)
	}

	return &ValidationError{
		Messages: errorMessages,
	}
}

// ValidationError represents multiple validation errors
type ValidationError struct {
	Messages []string
}

func (e *ValidationError) Error() string {
	return strings.Join(e.Messages, "; ")
}

// registerCustomValidations registers any custom validation functions
func registerCustomValidations(validate *validator.Validate) error {
	// Add custom validations here as needed
	// Example:
	// if err := validate.RegisterValidation("custom_tag", customValidationFunc); err != nil {
	//     return err
	// }
	return nil
}

// GetValidatorFromConfig creates a validator instance based on application config
func GetValidatorFromConfig(cfg *config.Config) (*Validator, error) {
	// For now, config doesn't affect validator creation
	// But this allows future configuration (e.g., language, strict mode)
	return NewValidator()
}
