// @oagen-ignore-file

package workos

import (
	
	
	
	
	
	
	
)

// AuthKitAuthorizationURLParams are parameters for building an AuthKit authorization URL.
type AuthKitAuthorizationURLParams struct {
	RedirectURI         string
	ClientID            string // if empty, uses client's configured clientID
	Provider            *string
	ConnectionID        *string
	OrganizationID      *string
	DomainHint          *string
	LoginHint           *string
	State               *string
	CodeChallenge       *string
	CodeChallengeMethod *string
	ScreenHint          *string
}

// GetAuthKitAuthorizationURL builds an AuthKit authorization URL.
// This is a helper that constructs the URL client-side without making an HTTP request.
func ( *Client) ( AuthKitAuthorizationURLParams) (string, error) {
	 := .ClientID
	if  == "" {
		 = .clientID
	}
	if  == "" {
		return "", fmt.Errorf("workos: client_id is required for AuthKit authorization URL")
	}
	if .RedirectURI == "" {
		return "", fmt.Errorf("workos: redirect_uri is required for AuthKit authorization URL")
	}

	 := .baseURL
	if  == "" {
		 = defaultBaseURL
	}

	,  := url.Parse( + "/user_management/authorize")
	if  != nil {
		return "", fmt.Errorf("workos: failed to parse authorization URL: %w", )
	}

	 := .Query()
	.Set("client_id", )
	.Set("redirect_uri", .RedirectURI)
	.Set("response_type", "code")

	if .Provider != nil {
		.Set("provider", *.Provider)
	}
	if .ConnectionID != nil {
		.Set("connection_id", *.ConnectionID)
	}
	if .OrganizationID != nil {
		.Set("organization_id", *.OrganizationID)
	}
	if .DomainHint != nil {
		.Set("domain_hint", *.DomainHint)
	}
	if .LoginHint != nil {
		.Set("login_hint", *.LoginHint)
	}
	if .State != nil {
		.Set("state", *.State)
	}
	if .CodeChallenge != nil {
		.Set("code_challenge", *.CodeChallenge)
	}
	if .CodeChallengeMethod != nil {
		.Set("code_challenge_method", *.CodeChallengeMethod)
	}
	if .ScreenHint != nil {
		.Set("screen_hint", *.ScreenHint)
	}

	.RawQuery = .Encode()
	return .String(), nil
}

// AuthKitPKCEAuthorizationURLResult contains the authorization URL plus the PKCE code verifier.
type AuthKitPKCEAuthorizationURLResult struct {
	URL          string
	CodeVerifier string
	State        string
}

// GetAuthKitPKCEAuthorizationURL generates PKCE parameters and builds an AuthKit authorization URL.
func ( *Client) ( AuthKitAuthorizationURLParams) (*AuthKitPKCEAuthorizationURLResult, error) {
	,  := GeneratePKCEPair()
	if  != nil {
		return nil, fmt.Errorf("workos: failed to generate PKCE pair: %w", )
	}

	.CodeChallenge = &.CodeChallenge
	.CodeChallengeMethod = &.CodeChallengeMethod

	// Generate a random state if not provided.
	 := ""
	if .State != nil {
		 = *.State
	} else {
		 := make([]byte, 32)
		if ,  := rand.Read();  != nil {
			return nil, fmt.Errorf("workos: failed to generate random state: %w", )
		}
		 = base64.RawURLEncoding.EncodeToString()
		.State = &
	}

	,  := .GetAuthKitAuthorizationURL()
	if  != nil {
		return nil, 
	}

	return &AuthKitPKCEAuthorizationURLResult{
		URL:          ,
		CodeVerifier: .CodeVerifier,
		State:        ,
	}, nil
}

// AuthKitPKCECodeExchangeParams holds the parameters for PKCE code exchange.
type AuthKitPKCECodeExchangeParams struct {
	Code         string
	CodeVerifier string
}

// AuthKitPKCECodeExchange exchanges an authorization code with a code verifier.
// This calls the authenticate endpoint with the code_verifier parameter.
func ( *Client) ( context.Context,  AuthKitPKCECodeExchangeParams,  ...RequestOption) (*AuthenticateResponse, error) {
	return .UserManagement().AuthenticateWithCode(, &UserManagementAuthenticateWithCodeParams{
		Code:         .Code,
		CodeVerifier: &.CodeVerifier,
	}, ...)
}

// AuthKitStartDeviceAuthorization initiates a device authorization flow (part 1).
func ( *Client) ( context.Context,  ...RequestOption) (*DeviceAuthorizationResponse, error) {
	return .UserManagement().CreateDevice(, &UserManagementCreateDeviceParams{
		ClientID: .clientID,
	}, ...)
}

// AuthKitPollDeviceCode polls for device code completion (part 2).
// Returns the authentication response once the user completes authorization.
// This method blocks until authorization completes, an error occurs, or the context is cancelled.
func ( *Client) ( context.Context,  string,  int,  ...RequestOption) (*AuthenticateResponse, error) {
	if  <= 0 {
		 = 5
	}

	 := time.NewTicker(time.Duration() * time.Second)
	defer .Stop()

	for {
		select {
		case <-.Done():
			return nil, .Err()
		case <-.C:
			,  := .UserManagement().AuthenticateWithDeviceCode(, &UserManagementAuthenticateWithDeviceCodeParams{
				DeviceCode: ,
			}, ...)
			if  != nil {
				// Check if this is an "authorization_pending" error; if so, keep polling.
				var  *APIError
				if errors.As(, &) && .Code == "authorization_pending" {
					continue
				}
				return nil, 
			}
			return , nil
		}
	}
}