package utils

import (
	"fmt"
	"strings"

	"github.com/go-playground/validator/v10"
)

var validate = validator.New()

// ValidationError represents a single validation error with user-friendly message
type ValidationError struct {
	Field   string `json:"field"`
	Message string `json:"message"`
	Tag     string `json:"tag"`
	Value   string `json:"value,omitempty"`
}

// ValidationResult contains validation results
type ValidationResult struct {
	IsValid bool                       `json:"is_valid"`
	Errors  map[string]ValidationError `json:"errors"`
	Count   int                        `json:"error_count"`
}

// ValidateStruct validates struct and returns user-friendly error messages
func ValidateStruct(s interface{}) []string {
	result := ValidateStructDetailed(s)
	var errors []string
	for _, err := range result.Errors {
		errors = append(errors, err.Message)
	}
	return errors
}

// ValidateStructDetailed validates struct and returns detailed validation result
func ValidateStructDetailed(s interface{}) ValidationResult {
	result := ValidationResult{
		IsValid: true,
		Errors:  make(map[string]ValidationError),
		Count:   0,
	}

	err := validate.Struct(s)
	if err != nil {
		result.IsValid = false

		for _, err := range err.(validator.ValidationErrors) {
			field := getFieldName(err.Field())
			validationErr := ValidationError{
				Field:   field,
				Message: getUserFriendlyMessage(err),
				Tag:     err.Tag(),
				Value:   fmt.Sprintf("%v", err.Value()),
			}

			result.Errors[field] = validationErr
			result.Count++
		}
	}

	return result
}

// getFieldName converts struct field name to user-friendly name
func getFieldName(field string) string {
	// Convert CamelCase to readable format
	var result strings.Builder
	for i, r := range field {
		if i > 0 && r >= 'A' && r <= 'Z' {
			result.WriteRune(' ')
		}
		if i == 0 {
			result.WriteRune(r)
		} else {
			result.WriteRune(r)
		}
	}
	return result.String()
}

// getUserFriendlyMessage converts validation error to user-friendly message
func getUserFriendlyMessage(err validator.FieldError) string {
	field := getFieldName(err.Field())

	switch err.Tag() {
	case "required":
		return fmt.Sprintf("%s is required", field)
	case "email":
		return fmt.Sprintf("%s must be a valid email address", field)
	case "min":
		return fmt.Sprintf("%s must be at least %s characters long", field, err.Param())
	case "max":
		return fmt.Sprintf("%s must not exceed %s characters", field, err.Param())
	case "len":
		return fmt.Sprintf("%s must be exactly %s characters long", field, err.Param())
	case "numeric":
		return fmt.Sprintf("%s must contain only numbers", field)
	case "alpha":
		return fmt.Sprintf("%s must contain only letters", field)
	case "alphanum":
		return fmt.Sprintf("%s must contain only letters and numbers", field)
	case "url":
		return fmt.Sprintf("%s must be a valid URL", field)
	case "uri":
		return fmt.Sprintf("%s must be a valid URI", field)
	case "gte":
		return fmt.Sprintf("%s must be greater than or equal to %s", field, err.Param())
	case "lte":
		return fmt.Sprintf("%s must be less than or equal to %s", field, err.Param())
	case "gt":
		return fmt.Sprintf("%s must be greater than %s", field, err.Param())
	case "lt":
		return fmt.Sprintf("%s must be less than %s", field, err.Param())
	case "oneof":
		return fmt.Sprintf("%s must be one of: %s", field, err.Param())
	case "unique":
		return fmt.Sprintf("%s must be unique", field)
	case "eqfield":
		return fmt.Sprintf("%s must match %s", field, err.Param())
	case "nefield":
		return fmt.Sprintf("%s must not match %s", field, err.Param())
	case "datetime":
		return fmt.Sprintf("%s must be a valid date and time", field)
	case "phone":
		return fmt.Sprintf("%s must be a valid phone number", field)
	default:
		return fmt.Sprintf("%s is invalid (rule: %s)", field, err.Tag())
	}
}

// ValidateField validates a single field value
func ValidateField(value interface{}, tag string) error {
	return validate.Var(value, tag)
}

// RegisterCustomValidation registers a custom validation function
func RegisterCustomValidation(tag string, fn validator.Func) error {
	return validate.RegisterValidation(tag, fn)
}

// Initialize custom validations
func init() {
	// Register custom phone validation
	validate.RegisterValidation("phone", func(fl validator.FieldLevel) bool {
		phone := fl.Field().String()
		if phone == "" {
			return true // Let required handle empty values
		}
		// Simple phone validation - adjust regex as needed
		// This allows: +62812345678, 0812345678, 812345678
		return len(phone) >= 10 && len(phone) <= 15
	})

	// Register custom Indonesian ID validation (NIK)
	validate.RegisterValidation("nik", func(fl validator.FieldLevel) bool {
		nik := fl.Field().String()
		if nik == "" {
			return true
		}
		// NIK must be exactly 16 digits
		return len(nik) == 16 && isNumeric(nik)
	})
}

// isNumeric checks if string contains only numbers
func isNumeric(s string) bool {
	for _, r := range s {
		if r < '0' || r > '9' {
			return false
		}
	}
	return true
}
