package gatewaycontroller

import (
	"github.com/creasty/defaults"
	"github.com/go-playground/validator/v10"
	"github.com/juju/errors"
	"github.com/pingcap/log"
	"github.com/spf13/viper"
	"go.uber.org/zap"
)

var (
	globalConf = &Config{}
	validate   = validator.New()
)

type Config struct {
	Namespace                       string   `mapstructure:"namespace" validate:"required"`
	Env                             string   `mapstructure:"env" validate:"required"`
	CloudProvider                   string   `mapstructure:"cloudProvider" validate:"required"`
	Region                          string   `mapstructure:"region" validate:"required"`
	ClusterName                     string   `mapstructure:"clusterName" validate:"required"`
	ImageRepo                       string   `mapstructure:"imageRepo" validate:"required"`
	InfraRedisAddr                  string   `mapstructure:"infraRedisAddr" validate:"required"`
	PushTrafficMetricsAddr          string   `mapstructure:"pushTrafficMetricsAddr"`
	PushTrafficMetricsInterval      int      `mapstructure:"pushTrafficMetricsInterval"`
	OtsInstanceName                 string   `mapstructure:"otsInstanceName"`
	InfraRegion                     string   `mapstructure:"infraRegion"`
	InfraRegionRole                 string   `mapstructure:"infraRegionRole"`
	DynamoDBEndpoint                string   `mapstructure:"dynamodbEndpoint"`
	TiDBServerVersion               string   `mapstructure:"tidbServerVersion"`
	EnableActiveConnectionDetection bool     `mapstructure:"enableActiveConnectionDetection"`
	EnableInfraMysqlClient          bool     `mapstructure:"enableInfraMysqlClient"`
	InfraRdsSecretArn               string   `mapstructure:"infraRdsSecretArn"`
	CacheServerAddr                 string   `mapstructure:"cacheServerAddr"`
	E2eEnv                          bool     `mapstructure:"e2eEnv"`
	KubeletVersion                  string   `mapstructure:"kubeletVersion"`
	FrontendReadTimeout             int      `mapstructure:"frontendReadTimeout"`
	TLSOnlySkipUserPrefixes         []string `mapstructure:"tlsOnlySkipUserPrefixes"`
	// ZoneAffinity configures zone affinity for each ingress class.
	// Map key is ingress class (e.g., "public", "privatelink", "privatelink-zr").
	// For AWS: uses logical zone names (primary, standby) with serverless.tidbcloud.com/zone label.
	// For AliCloud: uses actual zone names (e.g., us-east-1a) with topology.kubernetes.io/zone label.
	// If empty or ingress class not found, uses default behavior.
	ZoneAffinity map[string][]string `mapstructure:"zoneAffinity"`
}

// InitConfig parse the central configuration file and init the global config var
func InitConfig(path string) error {
	viper.SetConfigFile(path)
	viper.AutomaticEnv() // for M2M env variables
	if err := viper.ReadInConfig(); err != nil {
		return err
	}

	return NormalizeConfig()
}

func NormalizeConfigDefaults(config *Config) error {
	return defaults.Set(config)
}

func NormalizeConfigSetup(conf *Config) error {
	err := viper.Unmarshal(conf)
	if err != nil {
		return errors.Annotate(err, "failed unmarshal from viper")
	}

	return nil
}

func NormalizeConfigValidate(config *Config) error {
	// validate the values
	if err := validate.Struct(config); err != nil {
		return errors.Annotate(err, "failed to validate the config values")
	}
	return nil
}

func NormalizeConfig() error {
	config := &Config{}

	if err := NormalizeConfigDefaults(config); err != nil {
		return err
	}

	if err := NormalizeConfigSetup(config); err != nil {
		return err
	}

	if err := NormalizeConfigValidate(config); err != nil {
		return err
	}

	globalConf = config
	log.Info("normalize config", zap.Any("config", config))
	return nil
}

func Global() *Config {
	return globalConf
}
