package config

import (
	"fmt"

	"braces.dev/errtrace"
	"github.com/creasty/defaults"
	"github.com/go-playground/validator/v10"
	"github.com/spf13/viper"
)

// use defaults <- pulumi config (config file) <- remote config <- secrets
// defaults for tag default in the config struct.

// use a single instance of Validate, it caches struct info
var validate = validator.New()

func NormalizeConfigDefaults(config *TiDBMgmtPortalConfig) error {
	return errtrace.Wrap(defaults.Set(config))
}

func NormalizeConfigSetup(config *TiDBMgmtPortalConfig) error {
	err := viper.Unmarshal(config)
	if err != nil {
		return errtrace.Wrap(fmt.Errorf("failed unmarshal from viper: %w", err))
	}

	return nil
}

func NormalizeConfigValidate(config *TiDBMgmtPortalConfig) error {
	// validate the values
	if err := validate.Struct(config); err != nil {
		return errtrace.Wrap(fmt.Errorf("failed to validate the config values: %w", err))
	}
	return nil
}

func NormalizeConfig(validate bool) error {
	config := &TiDBMgmtPortalConfig{}

	err := NormalizeConfigDefaults(config)
	if err != nil {
		return errtrace.Wrap(err)
	}
	err = NormalizeConfigSetup(config)
	if err != nil {
		return errtrace.Wrap(err)
	}
	if validate {
		err = NormalizeConfigValidate(config)
		if err != nil {
			return errtrace.Wrap(err)
		}
	}
	globalConf = config
	return nil
}

func InitConfig(path string, validate bool) error {
	viper.SetConfigFile(path)
	viper.AutomaticEnv() // for M2M env variables
	err := viper.ReadInConfig()
	if err != nil {
		return errtrace.Wrap(err)
	}

	err = NormalizeConfig(validate)
	if err != nil {
		return errtrace.Wrap(err)
	}

	return nil
}

func Global() *TiDBMgmtPortalConfig {
	return globalConf
}
