package config

import (
	"fmt"
	"sync"

	"github.com/creasty/defaults"
	"github.com/spf13/viper"
)

var (
	confOnce sync.Once
	gConf    *Config
)

type Config struct {
	Server Server `mapstructure:"server"`
	GCP    GCP    `mapstructure:"gcp"`
}

type Server struct {
	SentryDSN          string   `mapstructure:"sentry_dsn"`
	SentryEnv          string   `mapstructure:"sentry_env"`
	SentryLogLevel     string   `mapstructure:"sentry_log_level"`
	Eventbus           Eventbus `mapstructure:"eventbus"`
	EnableIPv4Metering bool     `mapstructure:"enable_ipv4_metering" default:"false"`
}

type Eventbus struct {
	ProxyAddress    string `mapstructure:"proxy_address"`
	RetryTimes      uint   `mapstructure:"retry_times" default:"15"`
	NumOfGoroutines uint   `mapstructure:"num_of_goroutines" default:"5"`
}

type GCP struct {
	ProviderProjectID     string `mapstructure:"provider_project_id"`
	Location              string `mapstructure:"location"`
	PreAggregatedAWSTable string `mapstructure:"pre_aggregated_aws_table"`
	PreAggregatedGCPTable string `mapstructure:"pre_aggregated_gcp_table"`
}

func InitViper(filePath string) error {
	viper.SetConfigFile(filePath)
	viper.SetConfigType("yaml")

	err := viper.ReadInConfig()
	if err != nil {
		return fmt.Errorf("read config failed: %v", err)
	}
	return err
}

func GetConfig() *Config {
	confOnce.Do(func() {
		conf := &Config{}
		if err := defaults.Set(conf); err != nil {
			panic(fmt.Sprintf("set defaults: %s", err))
		}
		if err := viper.Unmarshal(conf); err != nil {
			panic(fmt.Sprintf("failed unmarshal from viper: %s", err))
		}

		gConf = conf
	})

	return gConf
}
