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
	}
	if siteID != "" {
		config.CLI.SiteID = siteID
	}

	return config, validate(config)
}

func (l *viperLoader) setDefaults(config *Config) error {
	if config.Database.Path == "" {
		config.Database.Path = "./insertr.db"
	}

	if config.CLI.SiteID == "" {
		config.CLI.SiteID = "demo"
	}

	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
}
