package config

import (
	"fmt"
	"os"
	"sync"

	"github.com/spf13/viper"
	_ "gopkg.in/yaml.v3"
)

const (
	YAML_PATH        = "infra/%s"
	ENV_MODE         = "ENV_MODE"
	DEFAULT_ENV_MODE = "development"
)

var (
	validEnvMode = map[string]struct{}{
		"local":       {},
		"development": {},
		"production":  {},
	}
)

type Config struct {
	Server   Server   `mapstructure:"server"`
	Database Database `mapstructure:"postgresql"`
	Jwt      Jwt      `mapstructure:"jwt"`
	Log      Log      `mapstructure:"log"`
	S3Config S3Config `mapstructure:"s3"`
}

var (
	config     *Config
	configOnce sync.Once
)

func LoadConfig() *Config {
	envMode := os.Getenv(ENV_MODE)
	if _, ok := validEnvMode[envMode]; !ok {
		envMode = DEFAULT_ENV_MODE
	}
	cfgFilePath := fmt.Sprintf(YAML_PATH, envMode)

	configOnce.Do(func() {
		v := viper.New()
		v.SetConfigType("yaml")
		v.AddConfigPath(".")
		v.SetConfigName(cfgFilePath)
		if err := v.ReadInConfig(); err != nil {
			panic(fmt.Errorf("failed to read config file: %s", err))
		}

		config = &Config{}
		if err := v.Unmarshal(config); err != nil {
			panic(fmt.Errorf("failed to unmarshal config: %s", err))
		}
	})

	return config
}

func (c *Config) Auth() *AuthConfig {
	return &AuthConfig{
		jwtTokenSecret:     c.Jwt.Token.Secret,
		jwtTokenExpiresTTL: c.Jwt.Token.ExpiresTTL,
	}
}

func (c *Config) LogLevel() string {
	return c.Log.LogLevel
}

func (c *Config) Port() string {
	return c.Server.Port
}

func (c *Config) LogFormat() string {
	return c.Log.LogFormat
}
