package spade

import "time"

const (
	// DefaultSpadeHost is the default URL that Spade events should be sent to.
	DefaultSpadeHost = "https://spade.internal.di.twitch.a2z.com"
	// DefaultBatchSize is the default number of tracking events that the client will send in a single request
	// to the Spade server.
	DefaultBatchSize = 32
	// DefaultTimeout the amount of time the client will wait for a request to the Spade server to complete.
	DefaultTimeout = time.Second * 10
	// DefaultBacklogSize is the default the number of tracking events the Spade client will queue up before
	// dropping events.
	DefaultBacklogSize = 1024
	// DefaultConcurrency is the default number of goroutines used to process queued events.
	DefaultConcurrency = 1
	// DefaultCombineSmallBatches is the default setting for the "combine small batches" feature.
	DefaultCombineSmallBatches = false
)

// Config defines the configuration info needed by the default Spade client implementation.
type Config interface {
	// GetSpadeHost returns a URL to the Spade server that tracking events should be sent to.
	GetSpadeHost() string
	// GetBatchSize returns the number of tracking events that the client will send in a single request to the
	// Spade server.
	GetBatchSize() int64
	// GetTimeout returns the amount of time the client will wait for a request to the Spade server to complete.
	GetTimeout() time.Duration
	// GetBacklogSize returns the number of tracking events the Spade client will queue up before dropping events.
	GetBacklogSize() int64
	// GetConcurrency returns the number of goroutines which should be used to process queued events.
	GetConcurrency() int64
	// CombineSmallBatchesEnabled indicates whether the feature to collect small batches before sending to Spade
	// is enabled.
	CombineSmallBatchesEnabled() bool
}

// StaticConfig is an implementation of Config that allows the consumer to configure the default Spade client
// implementation with fixed values.
type StaticConfig struct {
	// SpadeHost (optional) allows the consumer to set the URL to the Spade server that tracking events should be
	// sent to.  If left unset, DefaultSpadeHost is used instead.
	SpadeHost string
	// BatchSize (optional) allows the consumer to set the number of tracking events that the client will send in
	// a single request to the Spade server.  If left unset, DefaultBatchSize is used instead.
	BatchSize int64
	// Timeout (optional) allows the consumer to set the amount of time the client will wait for a request to the
	// Spade server to complete.  If left unset, DefaultTimeout is used instead.
	Timeout time.Duration
	// BacklogSize (optional) allows the consumer to set the number of tracking events the Spade client will queue
	// up before dropping events.  If left unset, DefaultBacklogSize is used instead.
	BacklogSize int64
	// Concurrency (optional) allows the consumer to set the number of goroutines used to process queued events.
	// If left unset, DefaultConcurrency is used.
	Concurrency int64
	// CombineSmallBatches (optional) enables a feature to reduce sending many small requests to Spade by introducing
	// a 50ms delay for a batch to collect more Events before allowing a worker to consume it.  This delay is
	// bypassed when the batch is full. If left unset, it is false by default.
	CombineSmallBatches bool
}

var _ Config = &StaticConfig{}

// GetSpadeHost returns a URL to the Spade server that tracking events should be sent to.
func (c *StaticConfig) GetSpadeHost() string {
	if c.SpadeHost == "" {
		return DefaultSpadeHost
	}
	return c.SpadeHost
}

// GetBatchSize returns the number of tracking events that the client will send in a single request to the
// Spade server.
func (c *StaticConfig) GetBatchSize() int64 {
	if c.BatchSize == 0 {
		return DefaultBatchSize
	}
	return c.BatchSize
}

// GetTimeout returns the amount of time the client will wait for a request to the Spade server to complete.
func (c *StaticConfig) GetTimeout() time.Duration {
	if c.Timeout == time.Duration(0) {
		return DefaultTimeout
	}
	return c.Timeout
}

// GetBacklogSize returns the number of tracking events the Spade client will queue up before dropping events.
func (c *StaticConfig) GetBacklogSize() int64 {
	if c.BacklogSize == 0 {
		return DefaultBacklogSize
	}
	return c.BacklogSize
}

// GetConcurrency returns the number of goroutines the Spade client will use to process queued events.
func (c *StaticConfig) GetConcurrency() int64 {
	if c.Concurrency <= 0 {
		return DefaultConcurrency
	}
	return c.Concurrency
}

// CombineSmallBatchesEnabled indicates whether the feature to collect small batches before sending to Spade is enabled.
func (c *StaticConfig) CombineSmallBatchesEnabled() bool {
	return c.CombineSmallBatches
}

// DynamicConfig is an implementation of Config that allows the consumer to update a Spade client's configuration
// at runtime.
type DynamicConfig struct {
	// SpadeHostFunc (optional) allows the consumer to set a function that returns the URL to the Spade server
	// that tracking events should be sent to.  If left unset, DefaultSpadeHost is used instead.
	SpadeHostFunc func() string
	// BatchSizeFunc (optional) allows the consumer to set a function that returns the number of tracking events
	// that the client will send in a single request to the Spade server.  If left unset, DefaultBatchSize is used
	// instead.
	BatchSizeFunc func() int64
	// TimeoutFunc (optional) allows the consumer to set a function that returns the amount of time the client will
	// wait for a request to the Spade server to complete.  If left unset, DefaultTimeout is used instead.
	TimeoutFunc func() time.Duration
	// BacklogSizeFunc (optional) allows the consumer to set  a function that returns  the number of tracking events
	// the Spade client will queue up before dropping events.  If left unset, DefaultBacklogSize is used instead.
	BacklogSizeFunc func() int64
	// Concurrency (optional) allows the consumer to set the number of goroutines used to process queued events.
	// If left unset, DefaultConcurrency is used. Unlike other parameters, this is not dynamic because the client
	// only initializes goroutines when calling Start().
	Concurrency int64
	// CombineSmallBatches (optional) enables a feature to reduce sending many small requests to Spade by introducing
	// a 50ms delay for a batch to collect more Events before allowing a worker to consume it.  This delay is
	// bypassed when the batch is full. If left unset, it is false by default.
	CombineSmallBatchesFunc func() bool
}

var _ Config = &DynamicConfig{}

// GetSpadeHost returns a URL to the Spade server that tracking events should be sent to.
func (c *DynamicConfig) GetSpadeHost() string {
	if c.SpadeHostFunc == nil {
		return DefaultSpadeHost
	}
	return c.SpadeHostFunc()
}

// GetBatchSize returns the number of tracking events that the client will send in a single request to the
// Spade server.
func (c *DynamicConfig) GetBatchSize() int64 {
	if c.BatchSizeFunc == nil {
		return DefaultBatchSize
	}
	return c.BatchSizeFunc()
}

// GetTimeout returns the amount of time the client will wait for a request to the Spade server to complete.
func (c *DynamicConfig) GetTimeout() time.Duration {
	if c.TimeoutFunc == nil {
		return DefaultTimeout
	}
	return c.TimeoutFunc()
}

// GetBacklogSize returns the number of tracking events the Spade client will queue up before dropping events.
func (c *DynamicConfig) GetBacklogSize() int64 {
	if c.BacklogSizeFunc == nil {
		return DefaultBacklogSize
	}
	return c.BacklogSizeFunc()
}

// GetConcurrency returns the number of goroutines the Spade client will use to process queued events.
func (c *DynamicConfig) GetConcurrency() int64 {
	if c.Concurrency <= 0 {
		return DefaultConcurrency
	}
	return c.Concurrency
}

// CombineSmallBatchesEnabled indicates whether the feature to collect small batches before sending to Spade is enabled.
func (c *DynamicConfig) CombineSmallBatchesEnabled() bool {
	if c.CombineSmallBatchesFunc == nil {
		return DefaultCombineSmallBatches
	}
	return c.CombineSmallBatchesFunc()
}
