package tenant

import (
	"strings"

	"github.com/pingcap/dbaas/central/config"
	"github.com/pingcap/dbaas/central/db/entity"
	"github.com/pingcap/dbaas/central/model/tenant"
	"github.com/pingcap/dbaas/central/service"
	"github.com/pingcap/errors"
	"github.com/tidbcloud/idl/pbgen/proto/central"
)

const (
	ErrIllegalRole = "The role is illegal."
	ErrEmptyEmail  = "The email address is empty."
)

// Company, Job and PhoneNumber fields could be empty
func validateRegistrationReq(req *central.RegistrationReq, isAuth0SocialConnection bool) error {
	connectionType := req.ConnectionType
	if connectionType == central.RegistrationReq_EMAIL {
		err := service.IsValidUsername(req.FirstName, req.LastName)
		if err != nil {
			return err
		}

		if req.Email == "" {
			return errors.New("user email cannot be empty")
		}

		if !service.IsValidEmail(req.Email) {
			return errors.New("user email address is invalid")
		}

		err = service.IsValidUserPassword(req.Password)
		if err != nil {
			return err
		}

		if config.Global().ServerConfig.EnableRecaptcha && req.RecaptchaResponse == "" {
			return errors.New("recaptcha response cannot be empty")
		}
	}

	if isAuth0SocialConnection {
		if req.Auth0Token == "" {
			return errors.New("auth0 token cannot be empty if connection type is social")
		}
	}

	if req.Company != "" {
		err := service.IsValidOrgName(req.Company)
		if err != nil {
			return err
		}
	}

	if req.Country == "" {
		return errors.New("country cannot be empty")
	}

	if !req.AcceptService {
		return errors.New("accept_service field must be true")
	}

	if (req.ThirdPartyAccountProvider == "") != (req.ThirdPartyAccountToken == "") {
		return errors.New("third_party_account_provider and third_party_account_token must be set at same time")
	}

	return nil
}

func isUTCOffsetValid(utcOffset int32) error {
	// https://en.wikipedia.org/wiki/List_of_UTC_time_offsets
	if utcOffset < -12 || utcOffset > 14 {
		return errors.Errorf("invalid timezone[%d], it should be an integer between -12 and 14", utcOffset)
	}
	return nil
}

func validateUpdateOrgReq(req *central.UpdateOrgReq) error {
	err := service.IsValidOrgName(req.Name)
	if err != nil {
		return err
	}
	err = isUTCOffsetValid(req.Timezone)
	if err != nil {
		return err
	}
	return nil
}

func IsValidUserRole(role entity.UserRole) error {
	_, exist := entity.ValidUserRoles[role]
	if !exist {
		return errors.New(ErrIllegalRole)
	}
	return nil
}

func validateInviteUserReq(req tenant.InviteUserReq) error {
	if len(req.EmailList) == 0 {
		return errors.New(ErrEmptyEmail)
	}

	failedEmailList := []string{}
	for _, email := range req.EmailList {
		isEmail := service.IsValidEmail(email)
		if !isEmail {
			failedEmailList = append(failedEmailList, email)
		}
	}
	if len(failedEmailList) != 0 {
		return errors.Errorf("The email address is invalid: %s.", strings.Join(failedEmailList, ", "))
	}

	return IsValidUserRole(req.Role)
}

func validateUpdateUserReq(req tenant.UpdateUserReq) error {
	return IsValidUserRole(req.Role)
}
