package config import ( "fmt" "github.com/spf13/viper" ) type Loader interface { Load(configFile string) (*Config, error) LoadWithDefaults() (*Config, error) LoadWithFlags(dbPath, apiURL, apiKey, siteID string) (*Config, error) } type viperLoader struct{} func NewLoader() Loader { return &viperLoader{} } func (l *viperLoader) Load(configFile string) (*Config, error) { v := viper.New() if configFile != "" { v.SetConfigFile(configFile) } else { v.AddConfigPath(".") v.SetConfigName("insertr") v.SetConfigType("yaml") } v.SetEnvPrefix("INSERTR") v.AutomaticEnv() if err := v.ReadInConfig(); err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); !ok { return nil, fmt.Errorf("failed to read config file: %w", err) } } config := &Config{} if err := v.Unmarshal(config); err != nil { return nil, fmt.Errorf("failed to unmarshal config: %w", err) } if err := l.setDefaults(config); err != nil { return nil, err } return config, validate(config) } func (l *viperLoader) LoadWithDefaults() (*Config, error) { return l.Load("") } func (l *viperLoader) LoadWithFlags(dbPath, apiURL, apiKey, siteID string) (*Config, error) { config, err := l.LoadWithDefaults() if err != nil { return nil, err } if dbPath != "" { config.Database.Path = dbPath } if apiURL != "" { config.API.URL = apiURL } if apiKey != "" { config.API.Key = apiKey } return config, validate(config) } func (l *viperLoader) setDefaults(config *Config) error { if config.Database.Path == "" { config.Database.Path = "./insertr.db" } if config.Server.Port == 0 { config.Server.Port = 8080 } if config.Server.Host == "" { config.Server.Host = "localhost" } if config.Auth.Provider == "" { config.Auth.Provider = "mock" } if config.Auth.JWTSecret == "" { config.Auth.JWTSecret = "dev-secret-change-in-production" config.Auth.DevMode = true } return nil }