package config

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

type Config struct {
	env map[string]string
}

type ConfigProvider interface {
	GetString(key string) string
	GetInt(key string) int
	GetBool(key string) bool
	GetDuration(key string) time.Duration
	GetServerAddress() string
	GetDatabaseDSN() string
	GetDatabaseDSNForLogging() string
	IsProduction() bool
	Validate() error
}

func NewConfig() ConfigProvider {
	env := make(map[string]string)
	
	// Load environment variables
	for _, pair := range os.Environ() {
		parts := strings.SplitN(pair, "=", 2)
		if len(parts) == 2 {
			env[parts[0]] = parts[1]
		}
	}

	// Set defaults
	setDefault(env, "FAAS_SERVER_HOST", "0.0.0.0")
	setDefault(env, "FAAS_SERVER_PORT", "8082")
	setDefault(env, "FAAS_DB_HOST", "localhost")
	setDefault(env, "FAAS_DB_PORT", "5432")
	setDefault(env, "FAAS_DB_NAME", "faas")
	setDefault(env, "FAAS_DB_USER", "postgres")
	setDefault(env, "FAAS_DB_PASSWORD", "postgres")
	setDefault(env, "FAAS_DB_SSLMODE", "disable")
	setDefault(env, "FAAS_APP_ENV", "development")
	setDefault(env, "FAAS_LOG_LEVEL", "debug")
	setDefault(env, "FAAS_DEFAULT_RUNTIME", "docker")
	setDefault(env, "FAAS_FUNCTION_TIMEOUT", "300s")
	setDefault(env, "FAAS_MAX_MEMORY", "3008")
	setDefault(env, "FAAS_MAX_CONCURRENT", "100")
	setDefault(env, "FAAS_SANDBOX_ENABLED", "true")
	setDefault(env, "FAAS_NETWORK_ISOLATION", "true")
	setDefault(env, "FAAS_RESOURCE_LIMITS", "true")
	setDefault(env, "SERVER_READ_TIMEOUT", "30s")
	setDefault(env, "SERVER_WRITE_TIMEOUT", "30s")
	setDefault(env, "SERVER_IDLE_TIMEOUT", "120s")
	setDefault(env, "RATE_LIMIT_ENABLED", "true")
	setDefault(env, "RATE_LIMIT_RPS", "100")
	setDefault(env, "RATE_LIMIT_BURST", "200")
	setDefault(env, "METRICS_ENABLED", "true")
	setDefault(env, "METRICS_PORT", "9091")
	setDefault(env, "AUTH_PROVIDER", "header")
	setDefault(env, "AUTH_HEADER_USER_EMAIL", "X-User-Email")

	return &Config{env: env}
}

func setDefault(env map[string]string, key, value string) {
	if _, exists := env[key]; !exists {
		env[key] = value
	}
}

func (c *Config) GetString(key string) string {
	return c.env[key]
}

func (c *Config) GetInt(key string) int {
	val := c.env[key]
	if val == "" {
		return 0
	}
	
	intVal, err := strconv.Atoi(val)
	if err != nil {
		return 0
	}
	
	return intVal
}

func (c *Config) GetBool(key string) bool {
	val := strings.ToLower(c.env[key])
	return val == "true" || val == "1" || val == "yes" || val == "on"
}

func (c *Config) GetDuration(key string) time.Duration {
	val := c.env[key]
	if val == "" {
		return 0
	}
	
	duration, err := time.ParseDuration(val)
	if err != nil {
		return 0
	}
	
	return duration
}

func (c *Config) GetServerAddress() string {
	host := c.GetString("FAAS_SERVER_HOST")
	port := c.GetString("FAAS_SERVER_PORT")
	return fmt.Sprintf("%s:%s", host, port)
}

func (c *Config) GetDatabaseDSN() string {
	host := c.GetString("FAAS_DB_HOST")
	port := c.GetString("FAAS_DB_PORT")
	name := c.GetString("FAAS_DB_NAME")
	user := c.GetString("FAAS_DB_USER")
	password := c.GetString("FAAS_DB_PASSWORD")
	sslmode := c.GetString("FAAS_DB_SSLMODE")
	
	return fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s",
		host, port, user, password, name, sslmode)
}

func (c *Config) GetDatabaseDSNForLogging() string {
	host := c.GetString("FAAS_DB_HOST")
	port := c.GetString("FAAS_DB_PORT")
	name := c.GetString("FAAS_DB_NAME")
	user := c.GetString("FAAS_DB_USER")
	sslmode := c.GetString("FAAS_DB_SSLMODE")
	
	return fmt.Sprintf("host=%s port=%s user=%s password=*** dbname=%s sslmode=%s",
		host, port, user, name, sslmode)
}

func (c *Config) IsProduction() bool {
	env := strings.ToLower(c.GetString("FAAS_APP_ENV"))
	return env == "production" || env == "prod"
}

func (c *Config) GetMetricsAddress() string {
	host := c.GetString("FAAS_SERVER_HOST")
	port := c.GetString("METRICS_PORT")
	return fmt.Sprintf("%s:%s", host, port)
}

func (c *Config) Validate() error {
	required := []string{
		"FAAS_SERVER_HOST",
		"FAAS_SERVER_PORT",
		"FAAS_DB_HOST",
		"FAAS_DB_PORT",
		"FAAS_DB_NAME",
		"FAAS_DB_USER",
		"FAAS_DB_PASSWORD",
	}
	
	for _, key := range required {
		if c.GetString(key) == "" {
			return fmt.Errorf("required environment variable %s is not set", key)
		}
	}
	
	// Validate server port
	if c.GetInt("FAAS_SERVER_PORT") <= 0 || c.GetInt("FAAS_SERVER_PORT") > 65535 {
		return fmt.Errorf("invalid server port: %s", c.GetString("FAAS_SERVER_PORT"))
	}
	
	// Validate database port
	if c.GetInt("FAAS_DB_PORT") <= 0 || c.GetInt("FAAS_DB_PORT") > 65535 {
		return fmt.Errorf("invalid database port: %s", c.GetString("FAAS_DB_PORT"))
	}
	
	// Validate timeout
	if c.GetDuration("FAAS_FUNCTION_TIMEOUT") <= 0 {
		return fmt.Errorf("invalid function timeout: %s", c.GetString("FAAS_FUNCTION_TIMEOUT"))
	}
	
	// Validate memory limit
	maxMemory := c.GetInt("FAAS_MAX_MEMORY")
	if maxMemory <= 0 || maxMemory > 10240 { // Max 10GB
		return fmt.Errorf("invalid max memory: %s", c.GetString("FAAS_MAX_MEMORY"))
	}
	
	return nil
}