// Code generated by Fern. DO NOT EDIT.

package client

import (
	context "context"
	fmt "fmt"
	management "github.com/auth0/go-auth0/v2/management"
	core "github.com/auth0/go-auth0/v2/management/core"
	internal "github.com/auth0/go-auth0/v2/management/internal"
	option "github.com/auth0/go-auth0/v2/management/option"
	authenticationmethods "github.com/auth0/go-auth0/v2/management/users/authenticationmethods"
	authenticators "github.com/auth0/go-auth0/v2/management/users/authenticators"
	connectedaccounts "github.com/auth0/go-auth0/v2/management/users/connectedaccounts"
	enrollments "github.com/auth0/go-auth0/v2/management/users/enrollments"
	federatedconnectionstokensets "github.com/auth0/go-auth0/v2/management/users/federatedconnectionstokensets"
	groups "github.com/auth0/go-auth0/v2/management/users/groups"
	identities "github.com/auth0/go-auth0/v2/management/users/identities"
	logs "github.com/auth0/go-auth0/v2/management/users/logs"
	multifactor "github.com/auth0/go-auth0/v2/management/users/multifactor"
	organizations "github.com/auth0/go-auth0/v2/management/users/organizations"
	permissions "github.com/auth0/go-auth0/v2/management/users/permissions"
	refreshtoken "github.com/auth0/go-auth0/v2/management/users/refreshtoken"
	riskassessments "github.com/auth0/go-auth0/v2/management/users/riskassessments"
	roles "github.com/auth0/go-auth0/v2/management/users/roles"
	sessions "github.com/auth0/go-auth0/v2/management/users/sessions"
	http "net/http"
	strconv "strconv"
)

type Client struct {
	WithRawResponse               *RawClient
	AuthenticationMethods         *authenticationmethods.Client
	Authenticators                *authenticators.Client
	ConnectedAccounts             *connectedaccounts.Client
	Enrollments                   *enrollments.Client
	FederatedConnectionsTokensets *federatedconnectionstokensets.Client
	Groups                        *groups.Client
	Identities                    *identities.Client
	Logs                          *logs.Client
	Multifactor                   *multifactor.Client
	Organizations                 *organizations.Client
	Permissions                   *permissions.Client
	RiskAssessments               *riskassessments.Client
	Roles                         *roles.Client
	RefreshToken                  *refreshtoken.Client
	Sessions                      *sessions.Client

	options *core.RequestOptions
	baseURL string
	caller  *internal.Caller
}

func NewClient(options *core.RequestOptions) *Client {
	return &Client{
		AuthenticationMethods:         authenticationmethods.NewClient(options),
		Authenticators:                authenticators.NewClient(options),
		ConnectedAccounts:             connectedaccounts.NewClient(options),
		Enrollments:                   enrollments.NewClient(options),
		FederatedConnectionsTokensets: federatedconnectionstokensets.NewClient(options),
		Groups:                        groups.NewClient(options),
		Identities:                    identities.NewClient(options),
		Logs:                          logs.NewClient(options),
		Multifactor:                   multifactor.NewClient(options),
		Organizations:                 organizations.NewClient(options),
		Permissions:                   permissions.NewClient(options),
		RiskAssessments:               riskassessments.NewClient(options),
		Roles:                         roles.NewClient(options),
		RefreshToken:                  refreshtoken.NewClient(options),
		Sessions:                      sessions.NewClient(options),
		WithRawResponse:               NewRawClient(options),
		options:                       options,
		baseURL:                       options.BaseURL,
		caller: internal.NewCaller(
			&internal.CallerParams{
				Client:      options.HTTPClient,
				MaxAttempts: options.MaxAttempts,
			},
		),
	}
}

// Retrieve details of users. It is possible to:
//
//   - Specify a search criteria for users
//   - Sort the users to be returned
//   - Select the fields to be returned
//   - Specify the number of users to retrieve per page and the page index
//     <!-- only v3 is available -->
//
// The <code>q</code> query parameter can be used to get users that match the specified criteria <a href="https://auth0.com/docs/users/search/v3/query-syntax">using query string syntax.</a>
//
// <a href="https://auth0.com/docs/users/search/v3">Learn more about searching for users.</a>
//
// Read about <a href="https://auth0.com/docs/users/search/best-practices">best practices</a> when working with the API endpoints for retrieving users.
//
// Auth0 limits the number of users you can return. If you exceed this threshold, please redefine your search, use the <a href="https://auth0.com/docs/api/management/v2#!/Jobs/post_users_exports">export job</a>, or the <a href="https://auth0.com/docs/extensions/user-import-export">User Import / Export</a> extension.
func (c *Client) List(
	ctx context.Context,
	request *management.ListUsersRequestParameters,
	opts ...option.RequestOption,
) (*core.Page[*management.UserResponseSchema], error) {
	options := core.NewRequestOptions(opts...)
	baseURL := internal.ResolveBaseURL(
		options.BaseURL,
		c.baseURL,
		"https://%7BTENANT%7D.auth0.com/api/v2",
	)
	endpointURL := baseURL + "/users"
	queryParams, err := internal.QueryValues(request)
	if err != nil {
		return nil, err
	}
	headers := internal.MergeHeaders(
		c.options.ToHeader(),
		options.ToHeader(),
	)
	prepareCall := func(pageRequest *internal.PageRequest[*int]) *internal.CallParams {
		if pageRequest.Cursor != nil {
			queryParams.Set("page", fmt.Sprintf("%v", *pageRequest.Cursor))
		}
		nextURL := endpointURL
		if len(queryParams) > 0 {
			nextURL += "?" + queryParams.Encode()
		}
		return &internal.CallParams{
			URL:             nextURL,
			Method:          http.MethodGet,
			Headers:         headers,
			MaxAttempts:     options.MaxAttempts,
			BodyProperties:  options.BodyProperties,
			QueryParameters: options.QueryParameters,
			Client:          options.HTTPClient,
			Response:        pageRequest.Response,
			ErrorDecoder:    internal.NewErrorDecoder(management.ErrorCodes),
		}
	}
	next := 1
	if queryParams.Has("page") {
		var err error
		if next, err = strconv.Atoi(queryParams.Get("page")); err != nil {
			return nil, err
		}
	}

	readPageResponse := func(response *management.ListUsersOffsetPaginatedResponseContent) *internal.PageResponse[*int, *management.UserResponseSchema] {
		next += 1
		results := response.Users
		return &internal.PageResponse[*int, *management.UserResponseSchema]{
			Next:    &next,
			Results: results,
		}
	}
	pager := internal.NewOffsetPager(
		c.caller,
		prepareCall,
		readPageResponse,
	)
	return pager.GetPage(ctx, &next)
}

// Create a new user for a given <a href="https://auth0.com/docs/connections/database">database</a> or <a href="https://auth0.com/docs/connections/passwordless">passwordless</a> connection.
//
// Note: <code>connection</code> is required but other parameters such as <code>email</code> and <code>password</code> are dependent upon the type of connection.
func (c *Client) Create(
	ctx context.Context,
	request *management.CreateUserRequestContent,
	opts ...option.RequestOption,
) (*management.CreateUserResponseContent, error) {
	response, err := c.WithRawResponse.Create(
		ctx,
		request,
		opts...,
	)
	if err != nil {
		return nil, err
	}
	return response.Body, nil
}

// Find users by email. If Auth0 is the identity provider (idP), the email address associated with a user is saved in lower case, regardless of how you initially provided it.
//
// For example, if you register a user as JohnSmith@example.com, Auth0 saves the user's email as johnsmith@example.com.
//
// Therefore, when using this endpoint, make sure that you are searching for users via email addresses using the correct case.
func (c *Client) ListUsersByEmail(
	ctx context.Context,
	request *management.ListUsersByEmailRequestParameters,
	opts ...option.RequestOption,
) ([]*management.UserResponseSchema, error) {
	response, err := c.WithRawResponse.ListUsersByEmail(
		ctx,
		request,
		opts...,
	)
	if err != nil {
		return nil, err
	}
	return response.Body, nil
}

// Retrieve user details. A list of fields to include or exclude may also be specified. For more information, see <a href="https://auth0.com/docs/manage-users/user-search/retrieve-users-with-get-users-endpoint">Retrieve Users with the Get Users Endpoint</a>.
func (c *Client) Get(
	ctx context.Context,
	// ID of the user to retrieve.
	id string,
	request *management.GetUserRequestParameters,
	opts ...option.RequestOption,
) (*management.GetUserResponseContent, error) {
	response, err := c.WithRawResponse.Get(
		ctx,
		id,
		request,
		opts...,
	)
	if err != nil {
		return nil, err
	}
	return response.Body, nil
}

// Delete a user by user ID. This action cannot be undone. For Auth0 Dashboard instructions, see <a href="https://auth0.com/docs/manage-users/user-accounts/delete-users">Delete Users</a>.
func (c *Client) Delete(
	ctx context.Context,
	// ID of the user to delete.
	id string,
	opts ...option.RequestOption,
) error {
	_, err := c.WithRawResponse.Delete(
		ctx,
		id,
		opts...,
	)
	if err != nil {
		return err
	}
	return nil
}

// Update a user.
//
// These are the attributes that can be updated at the root level:
//
// <ul>
//
//	<li>app_metadata</li>
//	<li>blocked</li>
//	<li>email</li>
//	<li>email_verified</li>
//	<li>family_name</li>
//	<li>given_name</li>
//	<li>name</li>
//	<li>nickname</li>
//	<li>password</li>
//	<li>phone_number</li>
//	<li>phone_verified</li>
//	<li>picture</li>
//	<li>username</li>
//	<li>user_metadata</li>
//	<li>verify_email</li>
//
// </ul>
//
// Some considerations:
// <ul>
//
//	<li>The properties of the new object will replace the old ones.</li>
//	<li>The metadata fields are an exception to this rule (<code>user_metadata</code> and <code>app_metadata</code>). These properties are merged instead of being replaced but be careful, the merge only occurs on the first level.</li>
//	<li>If you are updating <code>email</code>, <code>email_verified</code>, <code>phone_number</code>, <code>phone_verified</code>, <code>username</code> or <code>password</code> of a secondary identity, you need to specify the <code>connection</code> property too.</li>
//	<li>If you are updating <code>email</code> or <code>phone_number</code> you can specify, optionally, the <code>client_id</code> property.</li>
//	<li>Updating <code>email_verified</code> is not supported for enterprise and passwordless sms connections.</li>
//	<li>Updating the <code>blocked</code> to <code>false</code> does not affect the user's blocked state from an excessive amount of incorrectly provided credentials. Use the "Unblock a user" endpoint from the "User Blocks" API to change the user's state.</li>
//	<li>Supported attributes can be unset by supplying <code>null</code> as the value.</li>
//
// </ul>
//
// <h5>Updating a field (non-metadata property)</h5>
// To mark the email address of a user as verified, the body to send should be:
// <pre><code>{ "email_verified": true }</code></pre>
//
// <h5>Updating a user metadata root property</h5>Let's assume that our test user has the following <code>user_metadata</code>:
// <pre><code>{ "user_metadata" : { "profileCode": 1479 } }</code></pre>
//
// To add the field <code>addresses</code> the body to send should be:
// <pre><code>{ "user_metadata" : { "addresses": {"work_address": "100 Industrial Way"} }}</code></pre>
//
//	The modified object ends up with the following <code>user_metadata</code> property:<pre><code>{
//	  "user_metadata": {
//	    "profileCode": 1479,
//	    "addresses": { "work_address": "100 Industrial Way" }
//	  }
//	}</code></pre>
//
// <h5>Updating an inner user metadata property</h5>If there's existing user metadata to which we want to add  <code>"home_address": "742 Evergreen Terrace"</code> (using the <code>addresses</code> property) we should send the whole <code>addresses</code> object. Since this is a first-level object, the object will be merged in, but its own properties will not be. The body to send should be:
//
//	<pre><code>{
//	  "user_metadata": {
//	    "addresses": {
//	      "work_address": "100 Industrial Way",
//	      "home_address": "742 Evergreen Terrace"
//	    }
//	  }
//	}</code></pre>
//
// The modified object ends up with the following <code>user_metadata</code> property:
//
//	<pre><code>{
//	  "user_metadata": {
//	    "profileCode": 1479,
//	    "addresses": {
//	      "work_address": "100 Industrial Way",
//	      "home_address": "742 Evergreen Terrace"
//	    }
//	  }
//	}</code></pre>
func (c *Client) Update(
	ctx context.Context,
	// ID of the user to update.
	id string,
	request *management.UpdateUserRequestContent,
	opts ...option.RequestOption,
) (*management.UpdateUserResponseContent, error) {
	response, err := c.WithRawResponse.Update(
		ctx,
		id,
		request,
		opts...,
	)
	if err != nil {
		return nil, err
	}
	return response.Body, nil
}

// Remove an existing multi-factor authentication (MFA) <a href="https://auth0.com/docs/secure/multi-factor-authentication/reset-user-mfa">recovery code</a> and generate a new one. If a user cannot access the original device or account used for MFA enrollment, they can use a recovery code to authenticate.
func (c *Client) RegenerateRecoveryCode(
	ctx context.Context,
	// ID of the user to regenerate a multi-factor authentication recovery code for.
	id string,
	opts ...option.RequestOption,
) (*management.RegenerateUsersRecoveryCodeResponseContent, error) {
	response, err := c.WithRawResponse.RegenerateRecoveryCode(
		ctx,
		id,
		opts...,
	)
	if err != nil {
		return nil, err
	}
	return response.Body, nil
}

// Revokes selected resources related to a user (sessions, refresh tokens, ...).
func (c *Client) RevokeAccess(
	ctx context.Context,
	// ID of the user.
	id string,
	request *management.RevokeUserAccessRequestContent,
	opts ...option.RequestOption,
) error {
	_, err := c.WithRawResponse.RevokeAccess(
		ctx,
		id,
		request,
		opts...,
	)
	if err != nil {
		return err
	}
	return nil
}
