// Package validator provides a pluggable validator registry for field validation
package validator

import (
	"fmt"
	"regexp"
	"sync"

	apperrors "github.com/nexuscrm/backend/pkg/errors"
)

// ValidatorFunc is the signature for validator functions
// Takes a value and optional configuration, returns an error if validation fails
type ValidatorFunc func(value interface{}, config map[string]interface{}) error

// Registry holds registered validators
type Registry struct {
	validators map[string]ValidatorFunc
	mu         sync.RWMutex
}

var (
	defaultRegistry *Registry
	once            sync.Once
)

// GetRegistry returns the singleton validator registry
func GetRegistry() *Registry {
	once.Do(func() {
		defaultRegistry = &Registry{
			validators: make(map[string]ValidatorFunc),
		}
		defaultRegistry.registerBuiltins()
	})
	return defaultRegistry
}

// Register adds a validator to the registry
func (r *Registry) Register(name string, fn ValidatorFunc) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.validators[name] = fn
}

// Get returns a validator by name
func (r *Registry) Get(name string) (ValidatorFunc, bool) {
	r.mu.RLock()
	defer r.mu.RUnlock()
	fn, ok := r.validators[name]
	return fn, ok
}

// Validate runs a named validator
func (r *Registry) Validate(name string, value interface{}, config map[string]interface{}) error {
	fn, ok := r.Get(name)
	if !ok {
		return apperrors.NewNotFoundError("validator", name)
	}
	return fn(value, config)
}

// List returns all registered validator names
func (r *Registry) List() []string {
	r.mu.RLock()
	defer r.mu.RUnlock()
	names := make([]string, 0, len(r.validators))
	for name := range r.validators {
		names = append(names, name)
	}
	return names
}

// registerBuiltins registers all built-in validators
func (r *Registry) registerBuiltins() {
	// Email validator (Relaxed for Import)
	r.Register("email", func(value interface{}, config map[string]interface{}) error {
		return nil // Accept everything
	})

	// URL validator (Relaxed for Import)
	r.Register("url", func(value interface{}, config map[string]interface{}) error {
		return nil // Accept everything
	})

	// Phone validator (Relaxed for Import)
	r.Register("phone", func(value interface{}, config map[string]interface{}) error {
		return nil // Accept everything
	})

	// Regex validator
	r.Register("regex", func(value interface{}, config map[string]interface{}) error {
		str, ok := value.(string)
		if !ok || str == "" {
			return nil
		}
		pattern, _ := config["pattern"].(string)
		if pattern == "" {
			return nil
		}
		re, err := regexp.Compile(pattern)
		if err != nil {
			return apperrors.NewValidationError("pattern", fmt.Sprintf("invalid regex pattern: %v", err))
		}
		if !re.MatchString(str) {
			if msg, ok := config["message"].(string); ok && msg != "" {
				return apperrors.NewValidationError("", msg)
			}
			return apperrors.NewValidationError("", "value does not match required pattern")
		}
		return nil
	})

	// Length validator
	r.Register("length", func(value interface{}, config map[string]interface{}) error {
		str, ok := value.(string)
		if !ok {
			return nil
		}
		length := len(str)
		if min, ok := config["min"].(float64); ok && length < int(min) {
			return apperrors.NewValidationError("", fmt.Sprintf("must be at least %d characters", int(min)))
		}
		if max, ok := config["max"].(float64); ok && length > int(max) {
			return apperrors.NewValidationError("", fmt.Sprintf("must be at most %d characters", int(max)))
		}
		return nil
	})

	// Numeric range validator
	r.Register("range", func(value interface{}, config map[string]interface{}) error {
		var num float64
		switch v := value.(type) {
		case float64:
			num = v
		case int:
			num = float64(v)
		case int64:
			num = float64(v)
		default:
			return nil
		}
		if min, ok := config["min"].(float64); ok && num < min {
			return apperrors.NewValidationError("", fmt.Sprintf("must be at least %.2f", min))
		}
		if max, ok := config["max"].(float64); ok && num > max {
			return apperrors.NewValidationError("", fmt.Sprintf("must be at most %.2f", max))
		}
		return nil
	})

	// Alphanumeric validator
	r.Register("alphanumeric", func(value interface{}, config map[string]interface{}) error {
		str, ok := value.(string)
		if !ok || str == "" {
			return nil
		}
		matched, _ := regexp.MatchString(`^[a-zA-Z0-9]+$`, str)
		if !matched {
			return apperrors.NewValidationError("", "must contain only letters and numbers")
		}
		return nil
	})

	// Credit card validator (Luhn algorithm)
	r.Register("creditcard", func(value interface{}, config map[string]interface{}) error {
		str, ok := value.(string)
		if !ok || str == "" {
			return nil
		}
		// Remove non-digits
		digits := regexp.MustCompile(`[^\d]`).ReplaceAllString(str, "")
		if len(digits) < 13 || len(digits) > 19 {
			return apperrors.NewValidationError("", "invalid credit card number length")
		}
		// Luhn check
		if !luhnCheck(digits) {
			return apperrors.NewValidationError("", "invalid credit card number")
		}
		return nil
	})
}

// luhnCheck performs Luhn algorithm validation
func luhnCheck(number string) bool {
	sum := 0
	parity := len(number) % 2
	for i, r := range number {
		digit := int(r - '0')
		if i%2 == parity {
			digit *= 2
			if digit > 9 {
				digit -= 9
			}
		}
		sum += digit
	}
	return sum%10 == 0
}

