package clientutil

import (
	"context"
)

// BackendConfig specifies the configuration of a service backend.
//
// Services with multiple backends can be replicated or partitioned,
// depending on a configuration switch, making it a deployment-time
// decision. Clients are expected to compute their own sharding
// function (either by database lookup or other methods), and expose a
// 'shard' parameter on their APIs.
type BackendConfig struct {
	URL       string           `yaml:"url"`
	TLSConfig *TLSClientConfig `yaml:"tls"`
	Sharded   bool             `yaml:"sharded"`
	Debug     bool             `yaml:"debug"`
}

// Backend is a runtime class that provides http Clients for use with
// a specific service backend. If the service can't be partitioned,
// pass an empty string to the Call method.
type Backend interface {
	// Call a remote method. The sharding behavior is the following:
	//
	// Services that support sharding (partitioning) should always
	// include the shard ID in their Call() requests. Users can
	// then configure backends to be sharded or not in their
	// Config. When invoking Call with a shard ID on a non-sharded
	// service, the shard ID is simply ignored. Invoking Call
	// *without* a shard ID on a sharded service is an error.
	Call(context.Context, string, string, interface{}, interface{}) error

	// Close all resources associated with the backend.
	Close()
}

// NewBackend returns a new Backend with the given config.
func NewBackend(config *BackendConfig) (Backend, error) {
	return newBalancedBackend(config, defaultResolver)
}