package config

import (
	"strings"

	"github.com/spf13/viper"
)

type Config struct {
	Server   ServerConfig   `mapstructure:"server"`
	Database DatabaseConfig `mapstructure:"database"`
	S3       S3Config       `mapstructure:"s3"`
	Redis    RedisConfig    `mapstructure:"redis"`
}

type ServerConfig struct {
	Host string `mapstructure:"host"`
	Port int    `mapstructure:"port"`
}

type DatabaseConfig struct {
	Host     string `mapstructure:"host"`
	Port     int    `mapstructure:"port"`
	User     string `mapstructure:"user"`
	Password string `mapstructure:"password"`
	DBName   string `mapstructure:"dbname"`
	SSLMode  string `mapstructure:"sslmode"`
}

type S3Config struct {
	Endpoint        string `mapstructure:"endpoint"`
	Region          string `mapstructure:"region"`
	Bucket          string `mapstructure:"bucket"`
	AccessKeyID     string `mapstructure:"access_key_id"`
	SecretAccessKey string `mapstructure:"secret_access_key"`
	UsePathStyle    bool   `mapstructure:"use_path_style"`
}

type RedisConfig struct {
	Host     string `mapstructure:"host"`
	Port     int    `mapstructure:"port"`
	Password string `mapstructure:"password"`
	DB       int    `mapstructure:"db"`
}

func Load() (*Config, error) {
	viper.SetConfigName("config")
	viper.SetConfigType("yaml")
	viper.AddConfigPath(".")
	viper.AddConfigPath("/etc/orchard")

	// Environment variable overrides
	viper.SetEnvPrefix("ORCHARD")
	viper.AutomaticEnv()
	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

	// Bind environment variables explicitly for nested config
	viper.BindEnv("server.host", "ORCHARD_SERVER_HOST")
	viper.BindEnv("server.port", "ORCHARD_SERVER_PORT")
	viper.BindEnv("database.host", "ORCHARD_DATABASE_HOST")
	viper.BindEnv("database.port", "ORCHARD_DATABASE_PORT")
	viper.BindEnv("database.user", "ORCHARD_DATABASE_USER")
	viper.BindEnv("database.password", "ORCHARD_DATABASE_PASSWORD")
	viper.BindEnv("database.dbname", "ORCHARD_DATABASE_DBNAME")
	viper.BindEnv("database.sslmode", "ORCHARD_DATABASE_SSLMODE")
	viper.BindEnv("s3.endpoint", "ORCHARD_S3_ENDPOINT")
	viper.BindEnv("s3.region", "ORCHARD_S3_REGION")
	viper.BindEnv("s3.bucket", "ORCHARD_S3_BUCKET")
	viper.BindEnv("s3.access_key_id", "ORCHARD_S3_ACCESS_KEY_ID")
	viper.BindEnv("s3.secret_access_key", "ORCHARD_S3_SECRET_ACCESS_KEY")
	viper.BindEnv("s3.use_path_style", "ORCHARD_S3_USE_PATH_STYLE")
	viper.BindEnv("redis.host", "ORCHARD_REDIS_HOST")
	viper.BindEnv("redis.port", "ORCHARD_REDIS_PORT")
	viper.BindEnv("redis.password", "ORCHARD_REDIS_PASSWORD")
	viper.BindEnv("redis.db", "ORCHARD_REDIS_DB")

	// Defaults
	viper.SetDefault("server.host", "0.0.0.0")
	viper.SetDefault("server.port", 8080)
	viper.SetDefault("database.host", "localhost")
	viper.SetDefault("database.port", 5432)
	viper.SetDefault("database.user", "orchard")
	viper.SetDefault("database.dbname", "orchard")
	viper.SetDefault("database.sslmode", "disable")
	viper.SetDefault("s3.region", "us-east-1")
	viper.SetDefault("s3.bucket", "orchard-artifacts")
	viper.SetDefault("s3.use_path_style", true)
	viper.SetDefault("redis.host", "localhost")
	viper.SetDefault("redis.port", 6379)
	viper.SetDefault("redis.db", 0)

	if err := viper.ReadInConfig(); err != nil {
		if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
			return nil, err
		}
	}

	var cfg Config
	if err := viper.Unmarshal(&cfg); err != nil {
		return nil, err
	}

	return &cfg, nil
}
