package xray

import (
	"bytes"
	"fmt"
	"net"
	"os"
	"sync"
)

var config = &privateConfig{
	name:        os.Getenv("XRAY_TRACING_NAME"),
	defaultName: os.Getenv("XRAY_TRACING_DEFAULT_NAME"),
	daemonAddr: &net.UDPAddr{
		IP:   net.IPv4(127, 0, 0, 1),
		Port: 2000,
	},
	sampling: -1.0,
}

type privateConfig struct {
	sync.RWMutex

	name           string
	defaultName    string
	daemonAddr     *net.UDPAddr
	sampling       float64
	serviceVersion string
}

type Config struct {
	Name           string
	DefaultName    string
	DaemonAddr     string
	Sampling       float64 // To disable all tracing, set to a negative number
	ServiceVersion string
}

type MultiError []error

func (e MultiError) Error() string {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "%d errors occurred:\n", len(e))
	for _, err := range e {
		buf.WriteString("* ")
		buf.WriteString(err.Error())
		buf.WriteByte('\n')
	}
	return buf.String()
}

func Configure(c Config) error {
	config.Lock()
	defer config.Unlock()

	var errors MultiError

	if c.Name != "" {
		config.name = c.Name
	}
	if c.DefaultName != "" {
		config.defaultName = c.DefaultName
	}

	if c.DaemonAddr != "" {
		addr, err := net.ResolveUDPAddr("udp", c.DaemonAddr)
		if err == nil {
			config.daemonAddr = addr
			go refreshEmitter()
		} else {
			errors = append(errors, err)
		}
	}

	if c.Sampling != 0.0 {
		config.sampling = c.Sampling
	}

	if c.ServiceVersion != "" {
		config.serviceVersion = c.ServiceVersion
	}

	switch len(errors) {
	case 0:
		return nil
	case 1:
		return errors[0]
	default:
		return errors
	}
}

func (c *privateConfig) Name() string {
	c.RLock()
	defer c.RUnlock()
	return c.name
}

func (c *privateConfig) DefaultName() string {
	c.RLock()
	defer c.RUnlock()
	return c.defaultName
}

func (c *privateConfig) DaemonAddr() *net.UDPAddr {
	c.RLock()
	defer c.RUnlock()
	return c.daemonAddr
}

func (c *privateConfig) Sampling() float64 {
	c.RLock()
	defer c.RUnlock()
	return c.sampling
}

func (c *privateConfig) ServiceVersion() string {
	c.RLock()
	defer c.RUnlock()
	return c.serviceVersion
}
