// Package validate provides reusable input validation utilities with structured errors.
// It complements the sanitize package which focuses on security-critical sanitization.
// Use validate for business rule validation; use sanitize for security-critical input sanitization.
package validate

import (
	"fmt"
	"net/url"
	"regexp"
	"strings"
)

// ValidationError represents a single field validation failure.
type ValidationError struct {
	Field   string
	Message string
}

// Error implements the error interface.
func (e ValidationError) Error() string {
	return fmt.Sprintf("%s: %s", e.Field, e.Message)
}

// ValidationErrors is a collection of validation errors.
type ValidationErrors []ValidationError

// Error implements the error interface, returning all errors as a single message.
func (e ValidationErrors) Error() string {
	if len(e) == 0 {
		return ""
	}
	if len(e) == 1 {
		return e[0].Error()
	}

	var sb strings.Builder
	sb.WriteString("validation failed: ")
	for i, err := range e {
		if i > 0 {
			sb.WriteString("; ")
		}
		sb.WriteString(err.Error())
	}
	return sb.String()
}

// HasErrors returns true if there are any validation errors.
func (e ValidationErrors) HasErrors() bool {
	return len(e) > 0
}

// Fields returns a map of field names to their error messages.
// Useful for structured API error responses.
func (e ValidationErrors) Fields() map[string]string {
	result := make(map[string]string, len(e))
	for _, err := range e {
		// Only keep the first error per field
		if _, exists := result[err.Field]; !exists {
			result[err.Field] = err.Message
		}
	}
	return result
}

// Validator accumulates validation errors for composable validation.
type Validator struct {
	errors ValidationErrors
}

// New creates a new Validator for composable validation.
func New() *Validator {
	return &Validator{}
}

// Required validates that a string is not empty.
func (v *Validator) Required(value, field string) *Validator {
	if strings.TrimSpace(value) == "" {
		v.errors = append(v.errors, ValidationError{
			Field:   field,
			Message: "is required",
		})
	}
	return v
}

// RequiredSlice validates that a slice has at least one element.
func (v *Validator) RequiredSlice(value []string, field string) *Validator {
	if len(value) == 0 {
		v.errors = append(v.errors, ValidationError{
			Field:   field,
			Message: "is required",
		})
	}
	return v
}

// StringLength validates that a string's length is within bounds.
// Pass 0 for min to skip minimum check, or 0 for max to skip maximum check.
func (v *Validator) StringLength(value, field string, min, max int) *Validator {
	length := len(value)
	if min > 0 && length < min {
		v.errors = append(v.errors, ValidationError{
			Field:   field,
			Message: fmt.Sprintf("must be at least %d characters", min),
		})
	}
	if max > 0 && length > max {
		v.errors = append(v.errors, ValidationError{
			Field:   field,
			Message: fmt.Sprintf("must be at most %d characters", max),
		})
	}
	return v
}

// Pattern validates that a string matches a regular expression.
func (v *Validator) Pattern(value, field string, pattern *regexp.Regexp, description string) *Validator {
	if value != "" && !pattern.MatchString(value) {
		v.errors = append(v.errors, ValidationError{
			Field:   field,
			Message: description,
		})
	}
	return v
}

// Custom adds a custom validation check.
func (v *Validator) Custom(valid bool, field, message string) *Validator {
	if !valid {
		v.errors = append(v.errors, ValidationError{
			Field:   field,
			Message: message,
		})
	}
	return v
}

// AddError adds a validation error directly.
func (v *Validator) AddError(field, message string) *Validator {
	v.errors = append(v.errors, ValidationError{
		Field:   field,
		Message: message,
	})
	return v
}

// Error returns the accumulated validation errors, or nil if there are none.
func (v *Validator) Error() error {
	if len(v.errors) == 0 {
		return nil
	}
	return v.errors
}

// Errors returns the validation errors slice directly.
func (v *Validator) Errors() ValidationErrors {
	return v.errors
}

// HasErrors returns true if any validation errors have been recorded.
func (v *Validator) HasErrors() bool {
	return len(v.errors) > 0
}

// --- Standalone validation functions ---

// Required validates that a string is not empty.
// Returns a ValidationError if validation fails, nil otherwise.
func Required(value, field string) error {
	if strings.TrimSpace(value) == "" {
		return ValidationError{
			Field:   field,
			Message: "is required",
		}
	}
	return nil
}

// RequiredSlice validates that a slice has at least one element.
func RequiredSlice(value []string, field string) error {
	if len(value) == 0 {
		return ValidationError{
			Field:   field,
			Message: "is required",
		}
	}
	return nil
}

// StringLength validates that a string's length is within bounds.
// Pass 0 for min to skip minimum check, or 0 for max to skip maximum check.
func StringLength(value, field string, min, max int) error {
	length := len(value)
	if min > 0 && length < min {
		return ValidationError{
			Field:   field,
			Message: fmt.Sprintf("must be at least %d characters", min),
		}
	}
	if max > 0 && length > max {
		return ValidationError{
			Field:   field,
			Message: fmt.Sprintf("must be at most %d characters", max),
		}
	}
	return nil
}

// Pattern validates that a string matches a regular expression.
// Returns nil for empty strings (use Required for that check).
func Pattern(value, field string, pattern *regexp.Regexp, description string) error {
	if value != "" && !pattern.MatchString(value) {
		return ValidationError{
			Field:   field,
			Message: description,
		}
	}
	return nil
}

// --- Common patterns ---

// Common pre-compiled regex patterns for reuse.
var (
	// AlphanumericDashUnderscore matches alphanumeric strings with dashes and underscores.
	AlphanumericDashUnderscore = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)

	// AlphanumericDashUnderscoreDot matches alphanumeric strings with dashes, underscores, and dots.
	AlphanumericDashUnderscoreDot = regexp.MustCompile(`^[a-zA-Z0-9._-]+$`)

	// Email matches a basic email pattern.
	Email = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)

	// UUID matches a UUID format.
	UUID = regexp.MustCompile(`^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$`)

	// Slug matches URL-safe slugs (lowercase alphanumeric with dashes).
	Slug = regexp.MustCompile(`^[a-z0-9]+(?:-[a-z0-9]+)*$`)
)

// --- Convenience validators for common patterns ---

// HTTPURL validates that a string is a valid HTTP or HTTPS URL.
// Returns nil for empty strings (use Required for that check).
func HTTPURL(value, field string) error {
	if value == "" {
		return nil
	}
	parsed, err := url.Parse(value)
	if err != nil || (parsed.Scheme != "http" && parsed.Scheme != "https") || parsed.Host == "" {
		return ValidationError{
			Field:   field,
			Message: "must be a valid HTTP or HTTPS URL",
		}
	}
	return nil
}

// Name validates a name field (alphanumeric with dashes/underscores, 1-64 chars).
// This matches the existing isValidName pattern in claude_config.go.
func Name(value, field string) error {
	v := New()
	v.Required(value, field)
	v.StringLength(value, field, 1, 64)
	v.Pattern(value, field, AlphanumericDashUnderscore, "must be alphanumeric with dashes or underscores")
	return v.Error()
}

// IsValidationError returns true if the error is a ValidationError or ValidationErrors.
func IsValidationError(err error) bool {
	if err == nil {
		return false
	}
	switch err.(type) {
	case ValidationError, ValidationErrors:
		return true
	default:
		return false
	}
}

// AsValidationErrors converts an error to ValidationErrors if possible.
// Returns nil if the error is not a validation error.
func AsValidationErrors(err error) ValidationErrors {
	if err == nil {
		return nil
	}
	switch e := err.(type) {
	case ValidationErrors:
		return e
	case ValidationError:
		return ValidationErrors{e}
	default:
		return nil
	}
}
