package v3

import (
	"strings"
	"time"

	"github.com/rancher/norman/condition"
	"github.com/rancher/norman/types"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	UserConditionInitialRolesPopulated condition.Cond = "InitialRolesPopulated"
	AuthConfigConditionSecretsMigrated condition.Cond = "SecretsMigrated"
	// AuthConfigConditionShibbolethSecretFixed is applied to an AuthConfig when the
	// incorrect name for the shibboleth OpenLDAP secret has been fixed.
	AuthConfigConditionShibbolethSecretFixed condition.Cond = "ShibbolethSecretFixed"

	// AuthConfigOKTAPasswordMigrated is applied when an Okta password has been
	// moved to a Secret.
	AuthConfigOKTAPasswordMigrated condition.Cond = "OktaPasswordMigrated"
)

// +genclient
// +kubebuilder:skipversion
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type Token struct {
	metav1.TypeMeta    `json:",inline"`
	metav1.ObjectMeta  `json:"metadata,omitempty"`
	Token              string            `json:"token" norman:"writeOnly,noupdate"`
	UserPrincipal      Principal         `json:"userPrincipal" norman:"type=reference[principal]"`
	GroupPrincipals    []Principal       `json:"groupPrincipals,omitempty" norman:"type=array[reference[principal]]"`
	ProviderInfo       map[string]string `json:"providerInfo,omitempty"`
	UserID             string            `json:"userId" norman:"type=reference[user]"`
	AuthProvider       string            `json:"authProvider"`
	TTLMillis          int64             `json:"ttl"`
	LastUsedAt         *metav1.Time      `json:"lastUsedAt,omitempty"`
	ActivityLastSeenAt *metav1.Time      `json:"activityLastSeenAt,omitempty"`
	IsDerived          bool              `json:"isDerived"`
	Description        string            `json:"description"`
	Expired            bool              `json:"expired"`
	ExpiresAt          string            `json:"expiresAt"`
	Current            bool              `json:"current"`
	ClusterName        string            `json:"clusterName,omitempty" norman:"noupdate,type=reference[cluster]"`
	Enabled            *bool             `json:"enabled,omitempty" norman:"default=true"`
}

// Implement the TokenAccessor interface

func (t *Token) GetName() string {
	return t.ObjectMeta.Name
}

func (t *Token) GetIsEnabled() bool {
	return t.Enabled == nil || *t.Enabled
}

func (t *Token) GetIsDerived() bool {
	return t.IsDerived
}

func (t *Token) GetAuthProvider() string {
	return t.AuthProvider
}

func (t *Token) GetUserID() string {
	return t.UserID
}

func (t *Token) ObjClusterName() string {
	return t.ClusterName
}

func (t *Token) GetUserPrincipal() Principal {
	return t.UserPrincipal
}

func (t *Token) GetGroupPrincipals() []Principal {
	return t.GroupPrincipals
}

func (t *Token) GetProviderInfo() map[string]string {
	return t.ProviderInfo
}

func (t *Token) GetLastUsedAt() *metav1.Time {
	return t.LastUsedAt
}

func (t *Token) GetLastActivitySeen() *metav1.Time {
	return t.ActivityLastSeenAt
}

func (t *Token) GetCreationTime() metav1.Time {
	return t.CreationTimestamp
}

func (t *Token) GetExpiresAt() string {
	return t.ExpiresAt
}

func (t *Token) GetIsExpired() bool {
	if t.TTLMillis == 0 {
		return false
	}

	created := t.ObjectMeta.CreationTimestamp.Time
	durationElapsed := time.Since(created)

	ttlDuration := time.Duration(t.TTLMillis) * time.Millisecond
	return durationElapsed.Seconds() >= ttlDuration.Seconds()
}

// +genclient
// +genclient:nonNamespaced
// +kubebuilder:resource:scope=Cluster
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// User represents a user in Rancher
type User struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	// DisplayName is the user friendly name shown in the UI.
	// +optional
	DisplayName string `json:"displayName,omitempty"`
	// Description provides a brief summary about the user.
	// +optional
	Description string `json:"description"`
	// Username is the unique login identifier for the user.
	// +optional
	Username string `json:"username,omitempty"`
	// Deprecated. Password are stored in secrets in the cattle-local-user-passwords namespace.
	// +optional
	Password string `json:"password,omitempty" norman:"writeOnly,noupdate"`
	// MustChangePassword is a flag that, if true, forces the user to change their
	// password upon their next login.
	// +optional
	MustChangePassword bool `json:"mustChangePassword,omitempty"`
	// PrincipalIDs lists the authentication provider identities (e.g. GitHub, Keycloak or Active Directory)
	// that are associated with this user account.
	// +optional
	PrincipalIDs []string `json:"principalIds,omitempty" norman:"type=array[reference[principal]]"`
	// Deprecated. Only used by /v3 Rancher API.
	// +optional
	Me bool `json:"me,omitempty" norman:"nocreate,noupdate"`
	// Enabled indicates whether the user account is active.
	// +optional
	Enabled *bool `json:"enabled,omitempty" norman:"default=true"`
	// Status contains the most recent observed state of the user.
	// +optional
	Status UserStatus `json:"status"`
}

// IsSystem returns true if the user is a system user.
func (u *User) IsSystem() bool {
	for _, principalID := range u.PrincipalIDs {
		if strings.HasPrefix(principalID, "system:") {
			return true
		}
	}

	return false
}

// IsDefaultAdmin returns true if the user is the default admin user.
func (u *User) IsDefaultAdmin() bool {
	return u.Username == "admin"
}

// GetEnabled returns true if the user is enabled.
func (u *User) GetEnabled() bool {
	if u.Enabled == nil {
		return true // Enabled by default.
	}

	return *u.Enabled
}

type UserStatus struct {
	// +optional
	Conditions []UserCondition `json:"conditions"`
}

type UserCondition struct {
	// Type of user condition.
	Type string `json:"type"`
	// Status of the condition, one of True, False, Unknown.
	Status v1.ConditionStatus `json:"status"`
	// The last time this condition was updated.
	LastUpdateTime string `json:"lastUpdateTime,omitempty"`
	// Last time the condition transitioned from one status to another.
	LastTransitionTime string `json:"lastTransitionTime,omitempty"`
	// The reason for the condition's last transition.
	Reason string `json:"reason,omitempty"`
	// Human-readable message indicating details about last transition
	Message string `json:"message,omitempty"`
}

// +genclient
// +kubebuilder:skipversion
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// UserAttribute will have a CRD (and controller) generated for it, but will not be exposed in the API.
type UserAttribute struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	UserName        string
	GroupPrincipals map[string]Principals // the value is a []Principal, but code generator cannot handle slice as a value
	LastRefresh     string
	NeedsRefresh    bool
	ExtraByProvider map[string]map[string][]string // extra information for the user to print in audit logs, stored per authProvider. example: map[openldap:map[principalid:[openldap_user://uid=testuser1,ou=dev,dc=us-west-2,dc=compute,dc=internal]]]
	LastLogin       *metav1.Time                   `json:"lastLogin,omitempty"`
	DisableAfter    *metav1.Duration               `json:"disableAfter,omitempty"` // Overrides DisableInactiveUserAfter setting.
	DeleteAfter     *metav1.Duration               `json:"deleteAfter,omitempty"`  // Overrides DeleteInactiveUserAfter setting.
}

type Principals struct {
	Items []Principal
}

// +genclient
// +kubebuilder:skipversion
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type Group struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	DisplayName string `json:"displayName,omitempty"`
}

// +genclient
// +kubebuilder:skipversion
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type GroupMember struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	GroupName   string `json:"groupName,omitempty" norman:"type=reference[group]"`
	PrincipalID string `json:"principalId,omitempty" norman:"type=reference[principal]"`
}

// +genclient
// +kubebuilder:skipversion
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type Principal struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	DisplayName    string            `json:"displayName,omitempty"`
	LoginName      string            `json:"loginName,omitempty"`
	ProfilePicture string            `json:"profilePicture,omitempty"`
	ProfileURL     string            `json:"profileURL,omitempty"`
	PrincipalType  string            `json:"principalType,omitempty"`
	Me             bool              `json:"me,omitempty"`
	MemberOf       bool              `json:"memberOf,omitempty"`
	Provider       string            `json:"provider,omitempty"`
	ExtraInfo      map[string]string `json:"extraInfo,omitempty"`
}

type SearchPrincipalsInput struct {
	Name          string `json:"name" norman:"type=string,required,notnullable"`
	PrincipalType string `json:"principalType,omitempty" norman:"type=enum,options=user|group"`
}

type ChangePasswordInput struct {
	CurrentPassword string `json:"currentPassword" norman:"type=string,required"`
	NewPassword     string `json:"newPassword" norman:"type=string,required"`
}

type SetPasswordInput struct {
	NewPassword string `json:"newPassword" norman:"type=string,required"`
}

// +genclient
// +kubebuilder:skipversion
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type AuthConfig struct {
	metav1.TypeMeta   `json:",inline" mapstructure:",squash"`
	metav1.ObjectMeta `json:"metadata,omitempty" mapstructure:"metadata"`

	Type                string   `json:"type" norman:"noupdate"`
	Enabled             bool     `json:"enabled,omitempty"`
	AccessMode          string   `json:"accessMode,omitempty" norman:"required,notnullable,type=enum,options=required|restricted|unrestricted"`
	AllowedPrincipalIDs []string `json:"allowedPrincipalIds,omitempty" norman:"type=array[reference[principal]]"`

	// Flag. True when the auth provider supports a `Logout All` operation.
	// Currently only the SAML providers do, with their `Single Log Out` flow.
	LogoutAllSupported bool `json:"logoutAllSupported,omitempty"`

	Status AuthConfigStatus `json:"status"`
}

type AuthConfigStatus struct {
	Conditions []AuthConfigConditions `json:"conditions"`
}

type AuthConfigConditions struct {
	// Type of condition
	Type condition.Cond `json:"type"`

	// Status of condition (one of True, False, Unknown)
	Status v1.ConditionStatus `json:"status"`

	// Last time the condition was updated
	LastUpdateTime string `json:"lastUpdateTime,omitempty"`

	// Last time the condition transitioned from one status to another
	LastTransitionTime string `json:"lastTransitionTime,omitempty"`

	// The reason for the condition's last transition
	Reason string `json:"reason,omitempty"`

	// Human-readable message indicating details about last transition
	Message string `json:"message,omitempty"`
}

// +genclient
// +kubebuilder:skipversion
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type SamlToken struct {
	types.Namespaced
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Token     string `json:"token" norman:"writeOnly,noupdate"`
	ExpiresAt string `json:"expiresAt"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type LocalConfig struct {
	AuthConfig `json:",inline" mapstructure:",squash"`
}

// +genclient
// +kubebuilder:skipversion
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type GithubConfig struct {
	AuthConfig `json:",inline" mapstructure:",squash"`

	Hostname string `json:"hostname,omitempty" norman:"default=github.com,required"`
	TLS      bool   `json:"tls,omitempty" norman:"notnullable,default=true,required"`

	ClientID     string `json:"clientId,omitempty" norman:"required"`
	ClientSecret string `json:"clientSecret,omitempty" norman:"required,type=password"`

	// AdditionalClientIDs is a map of clientIDs to client secrets
	AdditionalClientIDs map[string]string `json:"additionalClientIds,omitempty" norman:"nocreate,noupdate"`
	HostnameToClientID  map[string]string `json:"hostnameToClientId,omitempty" norman:"nocreate,noupdate"`
}

type GithubConfigTestOutput struct {
	RedirectURL string `json:"redirectUrl"`
}

type GithubConfigApplyInput struct {
	GithubConfig GithubConfig `json:"githubConfig,omitempty"`
	Code         string       `json:"code,omitempty"`
	Enabled      bool         `json:"enabled,omitempty"`
}

// +genclient
// +kubebuilder:skipversion
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
//
// GithubAppConfig provides a combination of the GithubConfig and additional
// fields to configure the GitHub app for synchronization of user data.
type GithubAppConfig struct {
	AuthConfig `json:",inline" mapstructure:",squash"`

	// Hostname is the API server for the GitHub installation.
	Hostname string `json:"hostname,omitempty" norman:"default=github.com,required"`
	TLS      bool   `json:"tls,omitempty" norman:"notnullable,default=true,required"`

	ClientID     string `json:"clientId,omitempty" norman:"required"`
	ClientSecret string `json:"clientSecret,omitempty" norman:"required,type=password"`

	// AdditionalClientIDs is a map of clientIDs to client secrets
	AdditionalClientIDs map[string]string `json:"additionalClientIds,omitempty" norman:"nocreate,noupdate"`
	HostnameToClientID  map[string]string `json:"hostnameToClientId,omitempty" norman:"nocreate,noupdate"`

	// AppID is the GitHub App ID and is provided on the GitHub apps page.
	AppID string `json:"appId,omitempty" norman:"required"`

	// The Installation ID to query (this will be bound to a specific
	// Organization) and without it, we query all installations for the App.
	InstallationID string `json:"installationId,omitempty"`

	// PrivateKey is a PEM format private key for signing requests.
	PrivateKey string `json:"privateKey,omitempty" norman:"type=password,required"`
}

type GithubAppConfigTestOutput struct {
	RedirectURL string `json:"redirectUrl"`
}

type GithubAppConfigApplyInput struct {
	GithubConfig GithubAppConfig `json:"githubConfig,omitempty"`
	Code         string          `json:"code,omitempty"`
	Enabled      bool            `json:"enabled,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type GoogleOauthConfig struct {
	AuthConfig `json:",inline" mapstructure:",squash"`

	OauthCredential              string `json:"oauthCredential,omitempty" norman:"required,type=password,notnullable"`
	ServiceAccountCredential     string `json:"serviceAccountCredential,omitempty" norman:"required,type=password,notnullable"`
	AdminEmail                   string `json:"adminEmail,omitempty" norman:"required,notnullable"`
	Hostname                     string `json:"hostname,omitempty" norman:"required,notnullable,noupdate"`
	UserInfoEndpoint             string `json:"userInfoEndpoint" norman:"default=https://openidconnect.googleapis.com/v1/userinfo,required,notnullable"`
	NestedGroupMembershipEnabled bool   `json:"nestedGroupMembershipEnabled"    norman:"default=false"`
}

type GoogleOauthConfigTestOutput struct {
	RedirectURL string `json:"redirectUrl"`
}

type GoogleOauthConfigApplyInput struct {
	GoogleOauthConfig GoogleOauthConfig `json:"googleOauthConfig,omitempty"`
	Code              string            `json:"code,omitempty"`
	Enabled           bool              `json:"enabled,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type AzureADConfig struct {
	AuthConfig `json:",inline" mapstructure:",squash"`

	Endpoint              string `json:"endpoint,omitempty" norman:"default=https://login.microsoftonline.com/,required,notnullable"`
	GraphEndpoint         string `json:"graphEndpoint,omitempty" norman:"required,notnullable"`
	TokenEndpoint         string `json:"tokenEndpoint,omitempty" norman:"required,notnullable"`
	AuthEndpoint          string `json:"authEndpoint,omitempty" norman:"required,notnullable"`
	DeviceAuthEndpoint    string `json:"deviceAuthEndpoint,omitempty"`
	TenantID              string `json:"tenantId,omitempty" norman:"required,notnullable"`
	ApplicationID         string `json:"applicationId,omitempty" norman:"required,notnullable"`
	ApplicationSecret     string `json:"applicationSecret,omitempty" norman:"required,type=password"`
	RancherURL            string `json:"rancherUrl,omitempty" norman:"required,notnullable"`
	GroupMembershipFilter string `json:"groupMembershipFilter,omitempty"`
}

type AzureADConfigTestOutput struct {
	RedirectURL string `json:"redirectUrl"`
}

type AzureADConfigApplyInput struct {
	Config AzureADConfig `json:"config,omitempty"`
	Code   string        `json:"code,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type ActiveDirectoryConfig struct {
	AuthConfig `json:",inline" mapstructure:",squash"`

	Servers                      []string `json:"servers,omitempty"                     norman:"type=array[string],required"`
	Port                         int64    `json:"port,omitempty"                        norman:"default=389"`
	TLS                          bool     `json:"tls,omitempty"                         norman:"default=false"`
	StartTLS                     bool     `json:"starttls,omitempty"                    norman:"default=false"`
	Certificate                  string   `json:"certificate,omitempty"`
	DefaultLoginDomain           string   `json:"defaultLoginDomain,omitempty"`
	ServiceAccountUsername       string   `json:"serviceAccountUsername,omitempty"      norman:"required"`
	ServiceAccountPassword       string   `json:"serviceAccountPassword,omitempty"      norman:"type=password,required"`
	UserDisabledBitMask          int64    `json:"userDisabledBitMask,omitempty"         norman:"default=2"`
	UserSearchBase               string   `json:"userSearchBase,omitempty"              norman:"required"`
	UserSearchAttribute          string   `json:"userSearchAttribute,omitempty"         norman:"default=sAMAccountName|sn|givenName,required"`
	UserSearchFilter             string   `json:"userSearchFilter,omitempty"`
	UserLoginAttribute           string   `json:"userLoginAttribute,omitempty"          norman:"default=sAMAccountName,required"`
	UserObjectClass              string   `json:"userObjectClass,omitempty"             norman:"default=person,required"`
	UserNameAttribute            string   `json:"userNameAttribute,omitempty"           norman:"default=name,required"`
	UserEnabledAttribute         string   `json:"userEnabledAttribute,omitempty"        norman:"default=userAccountControl,required"`
	UserLoginFilter              string   `json:"userLoginFilter,omitempty"`
	GroupSearchBase              string   `json:"groupSearchBase,omitempty"`
	GroupSearchAttribute         string   `json:"groupSearchAttribute,omitempty"        norman:"default=sAMAccountName,required"`
	GroupSearchFilter            string   `json:"groupSearchFilter,omitempty"`
	GroupObjectClass             string   `json:"groupObjectClass,omitempty"            norman:"default=group,required"`
	GroupNameAttribute           string   `json:"groupNameAttribute,omitempty"          norman:"default=name,required"`
	GroupDNAttribute             string   `json:"groupDNAttribute,omitempty"            norman:"default=distinguishedName,required"`
	GroupMemberUserAttribute     string   `json:"groupMemberUserAttribute,omitempty"    norman:"default=distinguishedName,required"`
	GroupMemberMappingAttribute  string   `json:"groupMemberMappingAttribute,omitempty" norman:"default=member,required"`
	ConnectionTimeout            int64    `json:"connectionTimeout,omitempty"           norman:"default=5000,notnullable,required"`
	NestedGroupMembershipEnabled *bool    `json:"nestedGroupMembershipEnabled,omitempty" norman:"default=false"`
}

func (c *ActiveDirectoryConfig) GetUserSearchAttributes(searchAttributes ...string) []string {
	userSearchAttributes := []string{
		c.UserObjectClass,
		c.UserLoginAttribute,
		c.UserNameAttribute,
		c.UserEnabledAttribute,
	}
	return append(userSearchAttributes, searchAttributes...)
}

func (c *ActiveDirectoryConfig) GetGroupSearchAttributes(searchAttributes ...string) []string {
	groupSeachAttributes := []string{
		c.GroupObjectClass,
		c.UserLoginAttribute,
		c.GroupNameAttribute,
		c.GroupSearchAttribute,
	}
	return append(groupSeachAttributes, searchAttributes...)
}

type ActiveDirectoryTestAndApplyInput struct {
	ActiveDirectoryConfig ActiveDirectoryConfig `json:"activeDirectoryConfig,omitempty"`
	Username              string                `json:"username"`
	Password              string                `json:"password"`
	Enabled               bool                  `json:"enabled,omitempty"`
}

type LdapFields struct {
	Servers                         []string `json:"servers,omitempty"                         norman:"type=array[string],notnullable,required"`
	Port                            int64    `json:"port,omitempty"                            norman:"default=389,notnullable,required"`
	TLS                             bool     `json:"tls,omitempty"                             norman:"default=false,notnullable,required"`
	StartTLS                        bool     `json:"starttls,omitempty"                        norman:"default=false"`
	Certificate                     string   `json:"certificate,omitempty"`
	ServiceAccountDistinguishedName string   `json:"serviceAccountDistinguishedName,omitempty" norman:"required"`
	ServiceAccountPassword          string   `json:"serviceAccountPassword,omitempty"          norman:"type=password,required"`
	UserDisabledBitMask             int64    `json:"userDisabledBitMask,omitempty"`
	UserSearchBase                  string   `json:"userSearchBase,omitempty"                  norman:"notnullable,required"`
	UserSearchAttribute             string   `json:"userSearchAttribute,omitempty"             norman:"default=uid|sn|givenName,notnullable,required"`
	UserSearchFilter                string   `json:"userSearchFilter,omitempty"`
	UserLoginAttribute              string   `json:"userLoginAttribute,omitempty"              norman:"default=uid,notnullable,required"`
	UserObjectClass                 string   `json:"userObjectClass,omitempty"                 norman:"default=inetOrgPerson,notnullable,required"`
	UserNameAttribute               string   `json:"userNameAttribute,omitempty"               norman:"default=cn,notnullable,required"`
	UserMemberAttribute             string   `json:"userMemberAttribute,omitempty"             norman:"default=memberOf,notnullable,required"`
	UserEnabledAttribute            string   `json:"userEnabledAttribute,omitempty"`
	UserLoginFilter                 string   `json:"userLoginFilter,omitempty"`
	GroupSearchBase                 string   `json:"groupSearchBase,omitempty"`
	GroupSearchAttribute            string   `json:"groupSearchAttribute,omitempty"            norman:"default=cn,notnullable,required"`
	GroupSearchFilter               string   `json:"groupSearchFilter,omitempty"`
	GroupObjectClass                string   `json:"groupObjectClass,omitempty"                norman:"default=groupOfNames,notnullable,required"`
	GroupNameAttribute              string   `json:"groupNameAttribute,omitempty"              norman:"default=cn,notnullable,required"`
	GroupDNAttribute                string   `json:"groupDNAttribute,omitempty"                norman:"default=entryDN,notnullable"`
	GroupMemberUserAttribute        string   `json:"groupMemberUserAttribute,omitempty"        norman:"default=entryDN,notnullable"`
	GroupMemberMappingAttribute     string   `json:"groupMemberMappingAttribute,omitempty"     norman:"default=member,notnullable,required"`
	ConnectionTimeout               int64    `json:"connectionTimeout,omitempty"               norman:"default=5000,notnullable,required"`
	NestedGroupMembershipEnabled    bool     `json:"nestedGroupMembershipEnabled"              norman:"default=false"`
	SearchUsingServiceAccount       bool     `json:"searchUsingServiceAccount"       norman:"default=false"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type LdapConfig struct {
	AuthConfig `json:",inline" mapstructure:",squash"`
	LdapFields `json:",inline" mapstructure:",squash"`
}

func (c *LdapConfig) GetUserSearchAttributes(searchAttributes ...string) []string {
	userSearchAttributes := []string{
		"dn",
		c.UserMemberAttribute,
		c.UserObjectClass,
		c.UserLoginAttribute,
		c.UserNameAttribute,
		c.UserEnabledAttribute,
	}
	return append(userSearchAttributes, searchAttributes...)
}

func (c *LdapConfig) GetGroupSearchAttributes(searchAttributes ...string) []string {
	groupSeachAttributes := []string{
		c.GroupMemberUserAttribute,
		c.GroupObjectClass,
		c.UserLoginAttribute,
		c.GroupNameAttribute,
		c.GroupSearchAttribute,
	}
	return append(groupSeachAttributes, searchAttributes...)
}

type LdapTestAndApplyInput struct {
	LdapConfig `json:"ldapConfig,omitempty"`
	Username   string `json:"username"`
	Password   string `json:"password" norman:"type=password,required"`
}

type OpenLdapConfig struct {
	LdapConfig `json:",inline" mapstructure:",squash"`
}

type OpenLdapTestAndApplyInput struct {
	LdapTestAndApplyInput `json:",inline" mapstructure:",squash"`
}

type FreeIpaConfig struct {
	LdapConfig `json:",inline" mapstructure:",squash"`
}

type FreeIpaTestAndApplyInput struct {
	LdapTestAndApplyInput `json:",inline" mapstructure:",squash"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type SamlConfig struct {
	AuthConfig `json:",inline" mapstructure:",squash"`

	// Flag. True when the auth provider is configured to accept a `Logout All`
	// operation. Can be set if and only if the provider supports `Logout All`
	// (see AuthConfig.LogoutAllSupported).
	LogoutAllEnabled bool `json:"logoutAllEnabled,omitempty"`

	// Flag. Can be set if and only if `LogoutAllEnabled` (above) is set.
	// When set `Logout All` is the only kind of logout accepted. A regular
	// logout request will be rejected.
	LogoutAllForced bool `json:"logoutAllForced,omitempty"`

	IDPMetadataContent string `json:"idpMetadataContent" norman:"required"`
	SpCert             string `json:"spCert"             norman:"required"`
	SpKey              string `json:"spKey"              norman:"required,type=password"`
	GroupsField        string `json:"groupsField"        norman:"required"`
	DisplayNameField   string `json:"displayNameField"   norman:"required"`
	UserNameField      string `json:"userNameField"      norman:"required"`
	UIDField           string `json:"uidField"           norman:"required"`
	RancherAPIHost     string `json:"rancherApiHost"     norman:"required"`
	EntityID           string `json:"entityID"`
}

type SamlConfigTestInput struct {
	FinalRedirectURL string `json:"finalRedirectUrl"`
}

type SamlConfigTestOutput struct {
	IdpRedirectURL string `json:"idpRedirectUrl"`
}

type AuthConfigLogoutInput struct {
	FinalRedirectURL string `json:"finalRedirectUrl"`
}

type AuthConfigLogoutOutput struct {
	IdpRedirectURL string `json:"idpRedirectUrl"`
}

type PingConfig struct {
	SamlConfig `json:",inline" mapstructure:",squash"`
}

type ADFSConfig struct {
	SamlConfig `json:",inline" mapstructure:",squash"`
}

type KeyCloakConfig struct {
	SamlConfig `json:",inline" mapstructure:",squash"`
}

type OKTAConfig struct {
	SamlConfig     `json:",inline" mapstructure:",squash"`
	OpenLdapConfig LdapFields `json:"openLdapConfig"`
}

type ShibbolethConfig struct {
	SamlConfig     `json:",inline" mapstructure:",squash"`
	OpenLdapConfig LdapFields `json:"openLdapConfig"`
}

type AuthSystemImages struct {
	KubeAPIAuth string `json:"kubeAPIAuth,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type OIDCConfig struct {
	AuthConfig `json:",inline" mapstructure:",squash"`

	ClientID           string `json:"clientId" norman:"required"`
	ClientSecret       string `json:"clientSecret,omitempty" norman:"required,type=password"`
	RancherURL         string `json:"rancherUrl" norman:"required,notnullable"`
	Issuer             string `json:"issuer" norman:"required,notnullable"`
	AuthEndpoint       string `json:"authEndpoint,omitempty"`
	TokenEndpoint      string `json:"tokenEndpoint,omitempty"`
	UserInfoEndpoint   string `json:"userInfoEndpoint,omitempty"`
	JWKSUrl            string `json:"jwksUrl,omitempty"`
	Certificate        string `json:"certificate,omitempty"`
	PrivateKey         string `json:"privateKey,omitempty" norman:"type=password"`
	GroupSearchEnabled *bool  `json:"groupSearchEnabled"`
	// Scopes is expected to be a space delimited list of scopes
	Scopes string `json:"scope,omitempty"`
	// AcrValue is expected to be string containing the required ACR value
	AcrValue string `json:"acrValue,omitempty"`

	// This is provided by the OIDC Provider - it is the `end_session_uri` from
	// the discovery data.
	EndSessionEndpoint string `json:"endSessionEndpoint,omitempty"`
	// Flag. True when the auth provider is configured to accept a `Logout All`
	// operation. Can be set if and only if the provider supports `Logout All`
	// (see AuthConfig.LogoutAllSupported).
	LogoutAllEnabled bool `json:"logoutAllEnabled,omitempty"`

	// Flag. Can be set if and only if `LogoutAllEnabled` (above) is set.
	// When set `Logout All` is the only kind of logout accepted. A regular
	// logout request will be rejected.
	LogoutAllForced bool `json:"logoutAllForced,omitempty"`

	// GroupsClaim is used instead of groups
	GroupsClaim string `json:"groupsClaim,omitempty"`

	// NameClaim is used instead instead of the name claim.
	NameClaim string `json:"nameClaim,omitempty"`

	// EmailClaim is used instead of email
	EmailClaim string `json:"emailClaim,omitempty"`
}

type OIDCTestOutput struct {
	RedirectURL string `json:"redirectUrl"`
}

type OIDCApplyInput struct {
	OIDCConfig OIDCConfig `json:"oidcConfig,omitempty"`
	Code       string     `json:"code,omitempty"`
	Enabled    bool       `json:"enabled,omitempty"`
}

type KeyCloakOIDCConfig struct {
	OIDCConfig `json:",inline" mapstructure:",squash"`
}

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// ClusterProxyConfig determines which downstream requests will be proxied to the downstream cluster for requests that contain service account tokens.
// Objects of this type are created in the namespace of the target cluster.  If no object exists, the feature will be disabled by default.
type ClusterProxyConfig struct {
	types.Namespaced  `json:",inline"`
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	// Enabled indicates whether downstream proxy requests for service account tokens is enabled.
	Enabled bool `json:"enabled"`
}

// GenericOIDCConfig is the wrapper for the Generic OIDC provider to hold the OIDC Configuration
type GenericOIDCConfig struct {
	OIDCConfig `json:",inline" mapstructure:",squash"`
}

// GenericOIDCTestOutput is the wrapper for the Generic OIDC provider to hold the OIDC test output object, which
// in turn holds the RedirectURL
type GenericOIDCTestOutput struct {
	OIDCTestOutput `json:",inline" mapstructure:",squash"`
}

// GenericOIDCApplyInput is the wrapper for the input used to enable/activate the Generic OIDC auth provider.  It holds
// the configuration for the OIDC provider as well as an auth code.
type GenericOIDCApplyInput struct {
	OIDCApplyInput `json:",inline" mapstructure:",squash"`
}

// GenericOIDCConfig is a wrapper for the AWS Cognito provider holding the OIDC Configuration
type CognitoConfig struct {
	OIDCConfig `json:",inline" mapstructure:",squash"`
}
