package validation

import (
	"regexp"
	"time"

	"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
	"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)

const (
	firstNameMaxLength = 50
	lastNameMaxLength  = 50
	emailMaxLength     = 150

	memberNumberValidNumberOfLetters = 3
)

const (
	formModeVisit = 1
	formModeRide  = 2
)

func isAlphabetic(input string) bool {
	for _, character := range input {
		if !(characterIsUpperCase(character) || characterIsLowerCase(character)) {
			return false
		}
	}
	return true
}

func isNumeric(input string) bool {
	for _, character := range input {
		if !characterIsNumber(character) {
			return false
		}
	}

	return true
}

func isEmailValid(email string) bool {
	validEmailRegex := regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")

	return validEmailRegex.MatchString(email)
}

func isMemberNumberValid(input string) bool {
	if len(input) < memberNumberValidNumberOfLetters {
		return false
	}

	if !isAlphabetic(input[:memberNumberValidNumberOfLetters]) {
		return false
	}

	if !isNumeric(input[memberNumberValidNumberOfLetters:]) {
		return false
	}

	return true
}

func ValidateEligibility(user *viewmodel.User) []errors.ValidationError {
	var result []errors.ValidationError

	formMode := formModeVisit // This should be red from request, not hardcoded

	//First name validation
	if len(user.First) < 1 {
		result = append(result, errors.ValidationError{Field: "first", Message: "First Name is required"})
	}

	if !isAlphabetic(user.First) {
		result = append(result, errors.ValidationError{Field: "first", Message: "First Name contains non-alphabetic characters"})
	}

	if len(user.First) > firstNameMaxLength {
		result = append(result, errors.ValidationError{Field: "first", Message: "First Name is too long"})
	}

	//Last name validation
	if len(user.Last) < 1 {
		result = append(result, errors.ValidationError{Field: "last", Message: "Last Name is required"})
	}

	if !isAlphabetic(user.Last) {
		result = append(result, errors.ValidationError{Field: "last", Message: "Last Name contains non-alphabetic characters"})
	}

	if len(user.Last) > lastNameMaxLength {
		result = append(result, errors.ValidationError{Field: "last", Message: "Last Name is too long"})
	}

	//Email validation
	if user.Email != nil && len(*user.Email) > 0 {
		if (formMode == formModeRide) && len(*user.Email) < 1 {
			result = append(result, errors.ValidationError{Field: "email", Message: "Email is required"})
		}

		if !isEmailValid(*user.Email) {
			result = append(result, errors.ValidationError{Field: "email", Message: "Email is invalid"})
		}

		if len(*user.Email) > emailMaxLength {
			result = append(result, errors.ValidationError{Field: "email", Message: "Email is too long"})
		}
	} else {
		if formMode == formModeRide {
			result = append(result, errors.ValidationError{Field: "email", Message: "Email is required"})
		}
	}

	//Gender validation
	if ((user.Gender != nil) && len(*user.Gender) < 1) || (user.Gender == nil) {
		result = append(result, errors.ValidationError{Field: "gender", Message: "Member Gender is required"})
	}

	//Member type validation
	if (user.Type != nil && len(*user.Type) < 1) || (user.Type == nil) {
		result = append(result, errors.ValidationError{Field: "type", Message: "Member Type is required"})
	}

	//Member# validation
	if !isMemberNumberValid(*user.Member) {
		result = append(result, errors.ValidationError{Field: "member", Message: "Member# is invalid"})
	}
	//Birthdate validation
	if user.BirthDate == nil {
		result = append(result, errors.ValidationError{Field: "birthdate", Message: "Choose a Birth Date"})
	} else {
		yesterday := time.Now().Add(-1 * time.Hour * hoursInDay)
		if user.BirthDate.After(yesterday) {
			result = append(result, errors.ValidationError{Field: "birthdate", Message: "Choose a valid Birth Date"})
		}
	}
	//Mobile validation
	if formMode == formModeRide {
		if (user.PhoneNumber != nil && len(*user.PhoneNumber) < 1) || (user.PhoneNumber == nil) {
			result = append(result, errors.ValidationError{Field: "phonenumber", Message: "Phone number is required"})
		}
	}
	//User consent validation
	if !user.Consent {
		result = append(result, errors.ValidationError{Field: "consent", Message: "Must be 'Checked'"})
	}

	return result
}
