package errs

import (
	goerrors "errors"

	"github.com/go-errors/errors"
)

// errors and messages
var (
	// db
	ErrDBSeedFailure = goerrors.New("failed to seed db")

	// install
	ErrAlreadyInstalled = goerrors.New("already installed")

	// auth and permissions
	ErrAuthenticationFailed = goerrors.New("authentication failed")
	ErrAuthorizationFailed  = goerrors.New("authorization error")

	// mapping
	ErrMappingDBToEntityFailed = goerrors.New("failed to map db to entity")

	// audit
	ErrAuditFailedToSave = goerrors.New("failed to save audit")

	// user
	ErrUserWrongPasword      = goerrors.New("wrong password")
	ErrUserWrongTOTP         = goerrors.New("incorrect code")
	ErrUserWrongRecoveryCode = goerrors.New("incorrect recovery code")

	// session
	ErrSessionCookieNotFound = goerrors.New("session cookie not found")

	// campaign
	ErrCampaignAlreadySetToClose     = goerrors.New("campaign already set to closed")
	ErrCampaignAlreadyClosed         = goerrors.New("campaign already closed")
	ErrCampaignAlreadyAnonymized     = goerrors.New("campaign already anonymized")
	ErrCampaignDataAlreadyAnonymized = goerrors.New("campaign data already anonymized")

	// validation err
	ErrValidationFailed = goerrors.New("validation error")

	// license
	ErrLicenseMismatchSignature = goerrors.New("signature does not match")
	ErrLicenseExpired           = goerrors.New("expired")
	ErrLicenseEditionMismatch   = goerrors.New("edition does not match subscription")
	ErrLicenseNotValid          = goerrors.New("license is not valid")
	ErrLicenseRequestFailed     = goerrors.New("license request failed")
	ErrLicenseInvalidKey        = goerrors.New("invalid license key")

	// update
	ErrNoUpdateAvailable = goerrors.New("no update available")

	// sso
	ErrSSODisabled = goerrors.New("SSO disabled")
	// ErrSSOUserNotProvisioned is returned when an SSO login matches no existing
	// user, users are never auto provisioned and must be created by an admin first
	ErrSSOUserNotProvisioned = goerrors.New("SSO user not provisioned")
	// ErrSSOEmailNotVerified is returned when the provider has not verified the
	// email claim, an unverified email is not trusted for account matching
	ErrSSOEmailNotVerified = goerrors.New("SSO email not verified by provider")
	// ErrSSONoEmail is returned when the provider returns no email claim
	ErrSSONoEmail = goerrors.New("SSO provider returned no email")
	// ErrSSOMFARequired is returned when the authentication context returned by
	// the provider does not satisfy the required acr values
	ErrSSOMFARequired = goerrors.New("SSO authentication context requirement not met")
)

// format messages
const (
	MsgPasswordRenewRequired     = "New password required"
	MsgFailedToParseRequest      = "failed to parse request"
	MsgFailedToParseUUID         = "failed to parse uuid"
	MsgfFailedToParseCompanyUUID = "failed to parse company uuid: %s"
	MsgfFailedToMakeName         = "failed to make name: %s"
	MsgfFailedToParseTypeID      = "failed to parse message type uuid: %s"
	MsgfInvalidOffsetOrLimit     = "invalid offset or limit: %s"
)

func Wrap(err error) error {
	if err == nil {
		return nil
	}
	// we only wrap an error once
	if _, ok := err.(*errors.Error); ok {
		return err
	}
	return errors.Wrap(err, 0)
}

// ValidationError is a validation error
type ValidationError struct {
	Err error
}

// NewValidationError creates a new validation error
func NewValidationError(err error) error {
	return ValidationError{
		Err: err,
	}
}

// Error returns the validation error
func (e ValidationError) Error() string {
	return e.Err.Error()
}

// SyntaxError is returned when a request is structurally invalid (scim invalidSyntax)
type SyntaxError struct {
	Err error
}

// NewSyntaxError creates a new syntax error
func NewSyntaxError(err error) error {
	return SyntaxError{
		Err: err,
	}
}

// Error returns the syntax error
func (e SyntaxError) Error() string {
	return e.Err.Error()
}

// ConflictError is returned when a resource already exists (scim uniqueness conflict)
type ConflictError struct {
	Err error
}

// NewConflictError creates a new conflict error
func NewConflictError(err error) error {
	return ConflictError{
		Err: err,
	}
}

// Error returns the conflict error
func (e ConflictError) Error() string {
	return e.Err.Error()
}

// CustomError is a custom error
type CustomError struct {
	Err error
}

// NewCustomError creates a new custom error
// it is used when a custom error message should be
// returned to the consumer
func NewCustomError(err error) error {
	return CustomError{
		Err: err,
	}
}

// Error returns the custom error
func (e CustomError) Error() string {
	return e.Err.Error()
}
