package config

import (
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/joho/godotenv"
)

// ConfigProvider defines the interface for configuration operations
type ConfigProvider interface {
	GetString(key string) string
	GetInt(key string) int
	GetBool(key string) bool
	GetDuration(key string) time.Duration
	IsSet(key string) bool
	Validate() error
	GetDatabaseDSN() string
	GetDatabaseDSNForLogging() string
	GetServerAddress() string
	IsProduction() bool
}

// Config implements the ConfigProvider interface
type Config struct {
	defaults map[string]string
}

// NewConfig creates a new configuration instance
func NewConfig() ConfigProvider {
	// Load .env file if it exists
	_ = godotenv.Load()

	return &Config{
		defaults: map[string]string{
			"SERVER_HOST":            "0.0.0.0",
			"SERVER_PORT":            "8090",
			"SERVER_READ_TIMEOUT":    "30s",
			"SERVER_WRITE_TIMEOUT":   "30s",
			"SERVER_IDLE_TIMEOUT":    "60s",
			"DB_HOST":                "localhost",
			"DB_PORT":                "5432",
			"DB_NAME":                "users",
			"DB_USER":                "postgres",
			"DB_PASSWORD":            "postgres",
			"DB_SSLMODE":             "disable",
			"DB_MAX_OPEN_CONNS":      "25",
			"DB_MAX_IDLE_CONNS":      "5",
			"DB_CONN_MAX_LIFETIME":   "5m",
			"APP_ENV":                "development",
			"APP_VERSION":            "1.0.0",
			"LOG_LEVEL":              "debug",
			"RATE_LIMIT_ENABLED":     "true",
			"RATE_LIMIT_RPS":         "100",
			"RATE_LIMIT_BURST":       "200",
			"AUTH_PROVIDER":          "header",
			"AUTH_HEADER_USER_EMAIL": "X-User-Email",
		},
	}
}

func (c *Config) GetString(key string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return c.defaults[key]
}

func (c *Config) GetInt(key string) int {
	value := c.GetString(key)
	if value == "" {
		return 0
	}

	intVal, err := strconv.Atoi(value)
	if err != nil {
		return 0
	}
	return intVal
}

func (c *Config) GetBool(key string) bool {
	value := strings.ToLower(c.GetString(key))
	return value == "true" || value == "1"
}

func (c *Config) GetDuration(key string) time.Duration {
	value := c.GetString(key)
	if value == "" {
		return 0
	}

	duration, err := time.ParseDuration(value)
	if err != nil {
		return 0
	}
	return duration
}

func (c *Config) IsSet(key string) bool {
	return os.Getenv(key) != "" || c.defaults[key] != ""
}

func (c *Config) Validate() error {
	required := []string{
		"SERVER_HOST",
		"SERVER_PORT",
		"DB_HOST",
		"DB_PORT",
		"DB_NAME",
		"DB_USER",
		"DB_PASSWORD",
	}

	var missing []string
	for _, key := range required {
		if c.GetString(key) == "" {
			missing = append(missing, key)
		}
	}

	if len(missing) > 0 {
		return fmt.Errorf("missing required configuration keys: %s", strings.Join(missing, ", "))
	}

	return nil
}

func (c *Config) GetDatabaseDSN() string {
	host := c.GetString("DB_HOST")
	port := c.GetString("DB_PORT")
	user := c.GetString("DB_USER")
	password := c.GetString("DB_PASSWORD")
	dbname := c.GetString("DB_NAME")
	sslmode := c.GetString("DB_SSLMODE")

	// Debug logging to see what values we're getting
	// fmt.Printf("DEBUG DSN VALUES: host=%s port=%s user=%s password=%s dbname=%s sslmode=%s\n",
	// 	host, port, user, password, dbname, sslmode)

	dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s",
		host, port, user, password, dbname, sslmode)

	return dsn
}

func (c *Config) GetDatabaseDSNForLogging() string {
	return fmt.Sprintf("host=%s port=%s user=%s dbname=%s sslmode=%s",
		c.GetString("DB_HOST"),
		c.GetString("DB_PORT"),
		c.GetString("DB_USER"),
		c.GetString("DB_NAME"),
		c.GetString("DB_SSLMODE"),
	)
}

func (c *Config) GetServerAddress() string {
	return fmt.Sprintf("%s:%s", c.GetString("SERVER_HOST"), c.GetString("SERVER_PORT"))
}

func (c *Config) IsProduction() bool {
	return strings.ToLower(c.GetString("APP_ENV")) == "production"
}
