package validators

import (
	"errors"
	"regexp"
	"strings"

	"gorm.io/gorm"
	"veza-backend-api/internal/models"
)

// RFC 5322 compliant email regex (simplified but covers most cases)
// This regex validates:
// - Local part: alphanumeric, dots, underscores, hyphens, plus signs
// - @ symbol
// - Domain part: alphanumeric, dots, hyphens
// - TLD: at least 2 characters
var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)

// EmailValidator valide les emails selon RFC 5322
type EmailValidator struct {
	db *gorm.DB
}

// NewEmailValidator crée une nouvelle instance d'EmailValidator
func NewEmailValidator(db *gorm.DB) *EmailValidator {
	return &EmailValidator{db: db}
}

// ValidateFormat valide le format de l'email selon RFC 5322
func (v *EmailValidator) ValidateFormat(email string) bool {
	email = strings.ToLower(strings.TrimSpace(email))

	// RFC 5321: Email addresses are limited to 254 characters
	if len(email) > 254 {
		return false
	}

	// Vérifier que l'email n'est pas vide
	if len(email) == 0 {
		return false
	}

	// Vérifier le format avec regex
	if !emailRegex.MatchString(email) {
		return false
	}

	// Vérifications supplémentaires
	parts := strings.Split(email, "@")
	if len(parts) != 2 {
		return false
	}

	localPart := parts[0]
	domainPart := parts[1]

	// Local part ne peut pas être vide
	if len(localPart) == 0 || len(localPart) > 64 {
		return false
	}

	// Domain part ne peut pas être vide
	if len(domainPart) == 0 || len(domainPart) > 253 {
		return false
	}

	// Le domaine doit contenir au moins un point
	if !strings.Contains(domainPart, ".") {
		return false
	}

	// Le local part ne peut pas commencer ou finir par un point
	if strings.HasPrefix(localPart, ".") || strings.HasSuffix(localPart, ".") {
		return false
	}

	// Le domaine ne peut pas commencer ou finir par un point ou un tiret
	if strings.HasPrefix(domainPart, ".") || strings.HasSuffix(domainPart, ".") ||
		strings.HasPrefix(domainPart, "-") || strings.HasSuffix(domainPart, "-") {
		return false
	}

	return true
}

// IsUnique vérifie si l'email est unique en base de données
func (v *EmailValidator) IsUnique(email string) (bool, error) {
	email = strings.ToLower(strings.TrimSpace(email))

	var count int64
	err := v.db.Model(&models.User{}).
		Where("LOWER(email) = ?", email).
		Count(&count).Error

	if err != nil {
		return false, err
	}

	return count == 0, nil
}

// Validate effectue une validation complète de l'email (format + unicité)
func (v *EmailValidator) Validate(email string) error {
	if !v.ValidateFormat(email) {
		return errors.New("invalid email format")
	}

	unique, err := v.IsUnique(email)
	if err != nil {
		return err
	}

	if !unique {
		return errors.New("email already exists")
	}

	return nil
}
