package services_astrologer

import (
	"errors"
	"net/mail"
	"regexp"
	"strings"
)

// Validation for the credentials the OTP endpoints take.
//
// These used to be expressed as gin `binding` tags on the request DTOs, which
// rejected the payload with the validator's own text — "Key:
// 'VerifyMobileOTPRequest.OTP' Error:Field validation for 'OTP' failed on the
// 'len' tag" — and could not say anything about the shape of a mobile number or
// the first character of an email. The checks live here instead so both verify
// endpoints answer with a sentence, and so the same rule is applied wherever
// else it is needed.

// The mobile number rules live in mobile_validation.go, which checks a number
// against its own country code.

var (
	// Exactly six digits. Longer input is rejected outright rather than
	// compared and reported as a wrong OTP.
	otpPattern = regexp.MustCompile(`^[0-9]{6}$`)

	// The local part has to open with a letter or a digit — no leading dot,
	// underscore, plus or hyphen — and the domain has to carry a real TLD.
	// net/mail is permissive enough to accept things like "a@b", so it is used
	// for structure and this pattern for the rest.
	emailPattern = regexp.MustCompile(
		`^[A-Za-z0-9][A-Za-z0-9._%+\-]*@[A-Za-z0-9]([A-Za-z0-9\-]*[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9\-]*[A-Za-z0-9])?)*\.[A-Za-z]{2,}$`,
	)
)

// validateEmail checks the address and returns it trimmed and lower-cased.
func validateEmail(email string) (string, error) {

	trimmed := strings.TrimSpace(email)

	if trimmed == "" {
		return "", errors.New("email is required")
	}

	// ParseAddress also accepts a display name ("Name <a@b.com>"); only the
	// bare address is a valid login, so the parsed form has to come back
	// unchanged.
	address, err := mail.ParseAddress(trimmed)

	if err != nil || address.Name != "" || address.Address != trimmed {
		return "", errors.New(
			"please enter a valid email address, for example name@example.com",
		)
	}

	if !emailPattern.MatchString(trimmed) {
		return "", errors.New(
			"email must start with a letter or a number and be a valid address, for example name@example.com",
		)
	}

	return strings.ToLower(trimmed), nil
}

// validateOTP checks the code and returns it trimmed.
func validateOTP(otp string) (string, error) {

	trimmed := strings.TrimSpace(otp)

	if trimmed == "" {
		return "", errors.New("otp is required")
	}

	if !otpPattern.MatchString(trimmed) {
		return "", errors.New("otp must be exactly 6 digits")
	}

	return trimmed, nil
}
