package msgbus

import (
	"fmt"
	"os"

	"github.com/tidwall/wal"
)

const (
	// DefaultBind is the default bind address
	DefaultBind = ":8000"

	// DefaultLogPath is the default path to write logs to (wal)
	DefaultLogPath = "./logs"

	// DefaultMaxQueueSize is the default maximum size of queues
	DefaultMaxQueueSize = 1024 // ~8MB per queue (1000 * 4KB)

	// DefaultMaxPayloadSize is the default maximum payload size
	DefaultMaxPayloadSize = 8192 // 8KB

	// DefaultBufferLength is the default buffer length for subscriber chans
	DefaultBufferLength = 256

	// DefaultMetrics is the default for whether to enable metrics
	DefaultMetrics = false

	// DefaultNoSync is the default for whether to disable faync after writing
	// messages to the write-ahead-log (wal) files. The default is `false` which
	// is safer and will prevent corruption in event of crahses or power failure,
	// but is slower.
	DefaultNoSync = false
)

func NewDefaultOptions() *Options {
	return &Options{
		LogPath: DefaultLogPath,

		BufferLength:   DefaultBufferLength,
		MaxQueueSize:   DefaultMaxQueueSize,
		MaxPayloadSize: DefaultMaxPayloadSize,

		Metrics: DefaultMetrics,
		NoSync:  DefaultNoSync,
	}
}

// Options ...
type Options struct {
	LogPath string

	BufferLength   int
	MaxQueueSize   int
	MaxPayloadSize int

	Metrics bool
	NoSync  bool
}

type Option func(opts *Options) error

func WithLogPath(logPath string) Option {
	return func(opts *Options) error {
		if err := os.MkdirAll(logPath, 0755); err != nil {
			return fmt.Errorf("error creating log path %s: %w", logPath, err)
		}
		opts.LogPath = logPath
		return nil
	}
}

func WithBufferLength(bufferLength int) Option {
	return func(opts *Options) error {
		opts.BufferLength = bufferLength
		return nil
	}
}

func WithMaxQueueSize(maxQueueSize int) Option {
	return func(opts *Options) error {
		opts.MaxQueueSize = maxQueueSize
		return nil
	}
}

func WithMaxPayloadSize(maxPayloadSize int) Option {
	return func(opts *Options) error {
		opts.MaxPayloadSize = maxPayloadSize
		return nil
	}
}

func WithMetrics(metrics bool) Option {
	return func(opts *Options) error {
		opts.Metrics = metrics
		return nil
	}
}

func WithNoSync(noSync bool) Option {
	return func(opts *Options) error {
		wal.DefaultOptions.NoSync = noSync
		return nil
	}
}
