package tenant

import (
	"context"
	"strings"

	"github.com/tidbcloud/account/internel/controllers"
	tenant2 "github.com/tidbcloud/account/internel/svc/org/tenantctx"

	"github.com/tidbcloud/account/central/utils"
	accountErr "github.com/tidbcloud/account/commons/errors"
	"go.uber.org/zap"

	"github.com/tidbcloud/tiinf/monitor/tilog"

	"github.com/pingcap/errors"
	"github.com/tidbcloud/account/commons/config"
	"github.com/tidbcloud/account/idl/pbgen/proto/central"
	"github.com/tidbcloud/account/internel/dao/entity"
)

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

// Company, Job and PhoneNumber fields could be empty
func validateRegistrationReq(ctx context.Context, req *central.RegistrationReq, connectionType config.Auth0ConnectionType) error {
	if connectionType == config.Auth0DatabaseConnection {
		err := controllers.IsValidUsername(req.FirstName, req.LastName)
		if err != nil {
			return err
		}

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

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

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

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

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

	if req.Company != "" {
		err := controllers.IsValidOrgName(req.Company)
		if err != nil {
			// req.Company =org.name
			tilog.Info(ctx, "validate req.Company , the company is illegal ", zap.Any("req.Company", req.Company))
			return accountErr.NewErrMessageForFrontEnd("Please input a valid company name.", nil)

		}
	}

	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 {
	if req.Name != "" {
		err := controllers.IsValidOrgName(req.Name)
		if err != nil {
			return err
		}
	}

	if req.UserSetTimezone != "" {
		return utils.IsUserSetTimezoneValid(req.UserSetTimezone)
	}
	return nil
}

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

func IsValidUserOrgRbacRole(role string) error {
	_, exist := entity.ValidUserOrgRbacRoles[role]
	if !exist {
		return errors.New(ErrIllegalRole)
	}
	return nil
}

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

func IsValidUserProjectRbacRole(role string) error {
	_, exist := entity.ValidUserProjectRbacRoles[role]
	if !exist {
		return errors.New(ErrIllegalRole)
	}
	return nil
}

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

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

	if req.ProjectID != 0 {
		return IsValidUserProjectRbacRole(req.RbacRole)
	}
	return IsValidUserOrgRbacRole(req.RbacRole)
}

func validateUpdateUserReq(req tenant2.UpdateUserReq) error {
	return IsValidUserOrgRbacRole(req.RbacRole)
}
