// This file was auto-generated by Fern from our API Definition.

package client

import (
	context "context"
	fmt "fmt"
	http "net/http"
	url "net/url"
	sdk "sdk"
	core "sdk/core"
	datacenters "sdk/datacenters"
	envoys "sdk/envoys"
	health "sdk/health"
	metadata "sdk/metadata"
	namespaces "sdk/namespaces"
	runners "sdk/runners"
)

type Client struct {
	baseURL string
	caller  *core.Caller
	header  http.Header

	Datacenters *datacenters.Client
	Envoys      *envoys.Client
	Health      *health.Client
	Metadata    *metadata.Client
	Namespaces  *namespaces.Client
	Runners     *runners.Client
}

func NewClient(opts ...core.ClientOption) *Client {
	options := core.NewClientOptions()
	for _, opt := range opts {
		opt(options)
	}
	return &Client{
		baseURL:     options.BaseURL,
		caller:      core.NewCaller(options.HTTPClient),
		header:      options.ToHeader(),
		Datacenters: datacenters.NewClient(opts...),
		Envoys:      envoys.NewClient(opts...),
		Health:      health.NewClient(opts...),
		Metadata:    metadata.NewClient(opts...),
		Namespaces:  namespaces.NewClient(opts...),
		Runners:     runners.NewClient(opts...),
	}
}

// **If key is some & `include_destroyed` is false**
//
// 2 round trips:
//
// - namespace::ops::resolve_for_name_global
// - GET /actors (multiple DCs based on actor IDs)
//
//	This path is optimized because we can read the actor IDs fro the key directly from Epoxy with
//	stale consistency to determine which datacenter the actor lives in. Under most circumstances,
//	this means we don't need to fan out to all datacenters (like normal list does).
//
//	The reason `include_destroyed` has to be false is Epoxy only stores currently active actors. If
//	`include_destroyed` is true, we show all previous iterations of actors with the same key.
//
// **Otherwise**
//
// 2 round trips:
//
// - namespace::ops::resolve_for_name_global
// - GET /actors (fanout)
//
// ## Optimized Alternative Routes
func (c *Client) ActorsList(ctx context.Context, request *sdk.ActorsListRequest) (*sdk.ActorsListResponse, error) {
	baseURL := ""
	if c.baseURL != "" {
		baseURL = c.baseURL
	}
	endpointURL := baseURL + "/" + "actors"

	queryParams := make(url.Values)
	queryParams.Add("namespace", fmt.Sprintf("%v", request.Namespace))
	if request.Name != nil {
		queryParams.Add("name", fmt.Sprintf("%v", *request.Name))
	}
	if request.Key != nil {
		queryParams.Add("key", fmt.Sprintf("%v", *request.Key))
	}
	if request.ActorIds != nil {
		queryParams.Add("actor_ids", fmt.Sprintf("%v", *request.ActorIds))
	}
	for _, value := range request.ActorId {
		queryParams.Add("actor_id", fmt.Sprintf("%v", *value))
	}
	if request.IncludeDestroyed != nil {
		queryParams.Add("include_destroyed", fmt.Sprintf("%v", *request.IncludeDestroyed))
	}
	if request.Limit != nil {
		queryParams.Add("limit", fmt.Sprintf("%v", *request.Limit))
	}
	if request.Cursor != nil {
		queryParams.Add("cursor", fmt.Sprintf("%v", *request.Cursor))
	}
	if len(queryParams) > 0 {
		endpointURL += "?" + queryParams.Encode()
	}

	var response *sdk.ActorsListResponse
	if err := c.caller.Call(
		ctx,
		&core.CallParams{
			URL:      endpointURL,
			Method:   http.MethodGet,
			Headers:  c.header,
			Response: &response,
		},
	); err != nil {
		return nil, err
	}
	return response, nil
}

// **If actor is created in the current datacenter:**
//
// 2 round trips:
//
// - namespace::ops::resolve_for_name_global
// - [pegboard::workflows::actor] Create actor workflow (includes Epoxy key allocation)
//
// **If actor is created in a different datacenter:**
//
// 3 round trips:
//
// - namespace::ops::resolve_for_name_global
// - POST /actors to remote datacenter
// - [pegboard::workflows::actor] Create actor workflow (includes Epoxy key allocation)
//
// actor::get will always be in the same datacenter.
func (c *Client) ActorsCreate(ctx context.Context, request *sdk.ActorsCreateRequest) (*sdk.ActorsCreateResponse, error) {
	baseURL := ""
	if c.baseURL != "" {
		baseURL = c.baseURL
	}
	endpointURL := baseURL + "/" + "actors"

	queryParams := make(url.Values)
	queryParams.Add("namespace", fmt.Sprintf("%v", request.Namespace))
	if len(queryParams) > 0 {
		endpointURL += "?" + queryParams.Encode()
	}

	var response *sdk.ActorsCreateResponse
	if err := c.caller.Call(
		ctx,
		&core.CallParams{
			URL:      endpointURL,
			Method:   http.MethodPost,
			Headers:  c.header,
			Request:  request,
			Response: &response,
		},
	); err != nil {
		return nil, err
	}
	return response, nil
}

// **If actor exists**
//
// 2 round trips:
//
// - namespace::ops::resolve_for_name_global
// - GET /actors/{}
//
// **If actor does not exist and is created in the current datacenter:**
//
// 2 round trips:
//
// - namespace::ops::resolve_for_name_global
// - [pegboard::workflows::actor] Create actor workflow (includes Epoxy key allocation)
//
// **If actor does not exist and is created in a different datacenter:**
//
// 3 round trips:
//
// - namespace::ops::resolve_for_name_global
// - POST /actors to remote datacenter
// - [pegboard::workflows::actor] Create actor workflow (includes Epoxy key allocation)
//
// actor::get will always be in the same datacenter.
//
// ## Optimized Alternative Routes
func (c *Client) ActorsGetOrCreate(ctx context.Context, request *sdk.ActorsGetOrCreateRequest) (*sdk.ActorsGetOrCreateResponse, error) {
	baseURL := ""
	if c.baseURL != "" {
		baseURL = c.baseURL
	}
	endpointURL := baseURL + "/" + "actors"

	queryParams := make(url.Values)
	queryParams.Add("namespace", fmt.Sprintf("%v", request.Namespace))
	if len(queryParams) > 0 {
		endpointURL += "?" + queryParams.Encode()
	}

	var response *sdk.ActorsGetOrCreateResponse
	if err := c.caller.Call(
		ctx,
		&core.CallParams{
			URL:      endpointURL,
			Method:   http.MethodPut,
			Headers:  c.header,
			Request:  request,
			Response: &response,
		},
	); err != nil {
		return nil, err
	}
	return response, nil
}

// 2 round trips:
//
// - GET /actors/names (fanout)
// - [api-peer] namespace::ops::resolve_for_name_global
func (c *Client) ActorsListNames(ctx context.Context, request *sdk.ActorsListNamesRequest) (*sdk.ActorsListNamesResponse, error) {
	baseURL := ""
	if c.baseURL != "" {
		baseURL = c.baseURL
	}
	endpointURL := baseURL + "/" + "actors/names"

	queryParams := make(url.Values)
	queryParams.Add("namespace", fmt.Sprintf("%v", request.Namespace))
	if request.Limit != nil {
		queryParams.Add("limit", fmt.Sprintf("%v", *request.Limit))
	}
	if request.Cursor != nil {
		queryParams.Add("cursor", fmt.Sprintf("%v", *request.Cursor))
	}
	if len(queryParams) > 0 {
		endpointURL += "?" + queryParams.Encode()
	}

	var response *sdk.ActorsListNamesResponse
	if err := c.caller.Call(
		ctx,
		&core.CallParams{
			URL:      endpointURL,
			Method:   http.MethodGet,
			Headers:  c.header,
			Response: &response,
		},
	); err != nil {
		return nil, err
	}
	return response, nil
}

// 2 round trip:
//
// - DELETE /actors/{}
// - [api-peer] namespace::ops::resolve_for_name_global
func (c *Client) ActorsDelete(ctx context.Context, actorId sdk.RivetId, request *sdk.ActorsDeleteRequest) (sdk.ActorsDeleteResponse, error) {
	baseURL := ""
	if c.baseURL != "" {
		baseURL = c.baseURL
	}
	endpointURL := fmt.Sprintf(baseURL+"/"+"actors/%v", actorId)

	queryParams := make(url.Values)
	queryParams.Add("namespace", fmt.Sprintf("%v", request.Namespace))
	if len(queryParams) > 0 {
		endpointURL += "?" + queryParams.Encode()
	}

	var response sdk.ActorsDeleteResponse
	if err := c.caller.Call(
		ctx,
		&core.CallParams{
			URL:      endpointURL,
			Method:   http.MethodDelete,
			Headers:  c.header,
			Response: &response,
		},
	); err != nil {
		return nil, err
	}
	return response, nil
}

func (c *Client) ActorsKvGet(ctx context.Context, actorId sdk.RivetId, key string, request *sdk.ActorsKvGetRequest) (*sdk.ActorsKvGetResponse, error) {
	baseURL := ""
	if c.baseURL != "" {
		baseURL = c.baseURL
	}
	endpointURL := fmt.Sprintf(baseURL+"/"+"actors/%v/kv/keys/%v", actorId, key)

	queryParams := make(url.Values)
	queryParams.Add("namespace", fmt.Sprintf("%v", request.Namespace))
	if len(queryParams) > 0 {
		endpointURL += "?" + queryParams.Encode()
	}

	var response *sdk.ActorsKvGetResponse
	if err := c.caller.Call(
		ctx,
		&core.CallParams{
			URL:      endpointURL,
			Method:   http.MethodGet,
			Headers:  c.header,
			Response: &response,
		},
	); err != nil {
		return nil, err
	}
	return response, nil
}

func (c *Client) ActorsReschedule(ctx context.Context, actorId sdk.RivetId, request *sdk.ActorsRescheduleRequest) (sdk.ActorsRescheduleResponse, error) {
	baseURL := ""
	if c.baseURL != "" {
		baseURL = c.baseURL
	}
	endpointURL := fmt.Sprintf(baseURL+"/"+"actors/%v/reschedule", actorId)

	queryParams := make(url.Values)
	queryParams.Add("namespace", fmt.Sprintf("%v", request.Namespace))
	if len(queryParams) > 0 {
		endpointURL += "?" + queryParams.Encode()
	}

	var response sdk.ActorsRescheduleResponse
	if err := c.caller.Call(
		ctx,
		&core.CallParams{
			URL:      endpointURL,
			Method:   http.MethodPost,
			Headers:  c.header,
			Request:  request,
			Response: &response,
		},
	); err != nil {
		return nil, err
	}
	return response, nil
}

func (c *Client) ActorsSleep(ctx context.Context, actorId sdk.RivetId, request *sdk.ActorsSleepRequest) (sdk.ActorsSleepResponse, error) {
	baseURL := ""
	if c.baseURL != "" {
		baseURL = c.baseURL
	}
	endpointURL := fmt.Sprintf(baseURL+"/"+"actors/%v/sleep", actorId)

	queryParams := make(url.Values)
	queryParams.Add("namespace", fmt.Sprintf("%v", request.Namespace))
	if len(queryParams) > 0 {
		endpointURL += "?" + queryParams.Encode()
	}

	var response sdk.ActorsSleepResponse
	if err := c.caller.Call(
		ctx,
		&core.CallParams{
			URL:      endpointURL,
			Method:   http.MethodPost,
			Headers:  c.header,
			Request:  request,
			Response: &response,
		},
	); err != nil {
		return nil, err
	}
	return response, nil
}

func (c *Client) RunnerConfigsList(ctx context.Context, request *sdk.RunnerConfigsListRequest) (*sdk.RunnerConfigsListResponse, error) {
	baseURL := ""
	if c.baseURL != "" {
		baseURL = c.baseURL
	}
	endpointURL := baseURL + "/" + "runner-configs"

	queryParams := make(url.Values)
	queryParams.Add("namespace", fmt.Sprintf("%v", request.Namespace))
	if request.Limit != nil {
		queryParams.Add("limit", fmt.Sprintf("%v", *request.Limit))
	}
	if request.Cursor != nil {
		queryParams.Add("cursor", fmt.Sprintf("%v", *request.Cursor))
	}
	if request.Variant != nil {
		queryParams.Add("variant", fmt.Sprintf("%v", *request.Variant))
	}
	if request.RunnerNames != nil {
		queryParams.Add("runner_names", fmt.Sprintf("%v", *request.RunnerNames))
	}
	for _, value := range request.RunnerName {
		queryParams.Add("runner_name", fmt.Sprintf("%v", *value))
	}
	if len(queryParams) > 0 {
		endpointURL += "?" + queryParams.Encode()
	}

	var response *sdk.RunnerConfigsListResponse
	if err := c.caller.Call(
		ctx,
		&core.CallParams{
			URL:      endpointURL,
			Method:   http.MethodGet,
			Headers:  c.header,
			Response: &response,
		},
	); err != nil {
		return nil, err
	}
	return response, nil
}

func (c *Client) RunnerConfigsServerlessHealthCheck(ctx context.Context, request *sdk.RunnerConfigsServerlessHealthCheckRequest) (*sdk.RunnerConfigsServerlessHealthCheckResponse, error) {
	baseURL := ""
	if c.baseURL != "" {
		baseURL = c.baseURL
	}
	endpointURL := baseURL + "/" + "runner-configs/serverless-health-check"

	queryParams := make(url.Values)
	queryParams.Add("namespace", fmt.Sprintf("%v", request.Namespace))
	if len(queryParams) > 0 {
		endpointURL += "?" + queryParams.Encode()
	}

	var response *sdk.RunnerConfigsServerlessHealthCheckResponse
	if err := c.caller.Call(
		ctx,
		&core.CallParams{
			URL:      endpointURL,
			Method:   http.MethodPost,
			Headers:  c.header,
			Request:  request,
			Response: &response,
		},
	); err != nil {
		return nil, err
	}
	return response, nil
}

func (c *Client) RunnerConfigsUpsert(ctx context.Context, runnerName string, request *sdk.RunnerConfigsUpsertRequestBody) (*sdk.RunnerConfigsUpsertResponse, error) {
	baseURL := ""
	if c.baseURL != "" {
		baseURL = c.baseURL
	}
	endpointURL := fmt.Sprintf(baseURL+"/"+"runner-configs/%v", runnerName)

	queryParams := make(url.Values)
	queryParams.Add("namespace", fmt.Sprintf("%v", request.Namespace))
	if len(queryParams) > 0 {
		endpointURL += "?" + queryParams.Encode()
	}

	var response *sdk.RunnerConfigsUpsertResponse
	if err := c.caller.Call(
		ctx,
		&core.CallParams{
			URL:      endpointURL,
			Method:   http.MethodPut,
			Headers:  c.header,
			Request:  request,
			Response: &response,
		},
	); err != nil {
		return nil, err
	}
	return response, nil
}

func (c *Client) RunnerConfigsDelete(ctx context.Context, runnerName string, request *sdk.RunnerConfigsDeleteRequest) (sdk.RunnerConfigsDeleteResponse, error) {
	baseURL := ""
	if c.baseURL != "" {
		baseURL = c.baseURL
	}
	endpointURL := fmt.Sprintf(baseURL+"/"+"runner-configs/%v", runnerName)

	queryParams := make(url.Values)
	queryParams.Add("namespace", fmt.Sprintf("%v", request.Namespace))
	if len(queryParams) > 0 {
		endpointURL += "?" + queryParams.Encode()
	}

	var response sdk.RunnerConfigsDeleteResponse
	if err := c.caller.Call(
		ctx,
		&core.CallParams{
			URL:      endpointURL,
			Method:   http.MethodDelete,
			Headers:  c.header,
			Response: &response,
		},
	); err != nil {
		return nil, err
	}
	return response, nil
}

func (c *Client) RunnerConfigsRefreshMetadata(ctx context.Context, runnerName string, request *sdk.RunnerConfigsRefreshMetadataRequest) (sdk.RunnerConfigsRefreshMetadataResponse, error) {
	baseURL := ""
	if c.baseURL != "" {
		baseURL = c.baseURL
	}
	endpointURL := fmt.Sprintf(baseURL+"/"+"runner-configs/%v/refresh-metadata", runnerName)

	queryParams := make(url.Values)
	queryParams.Add("namespace", fmt.Sprintf("%v", request.Namespace))
	if len(queryParams) > 0 {
		endpointURL += "?" + queryParams.Encode()
	}

	var response sdk.RunnerConfigsRefreshMetadataResponse
	if err := c.caller.Call(
		ctx,
		&core.CallParams{
			URL:      endpointURL,
			Method:   http.MethodPost,
			Headers:  c.header,
			Request:  request,
			Response: &response,
		},
	); err != nil {
		return nil, err
	}
	return response, nil
}
