package config

import (
	"fmt"
	"os"
	"strconv"
	"strings"
)

// Config holds world server configuration loaded from environment.
type Config struct {
	Env      string
	Debug    bool
	Host     string
	Port     int
	LogLevel string
	LogPath  string
	TickMS   int

	RedisHost     string
	RedisPort     int
	RedisPassword string

	MySQLHost     string
	MySQLPort     int
	MySQLDatabase string
	MySQLUser     string
	MySQLPassword string

	WSTicketTTLSeconds int
}

// Load reads configuration from environment variables with sensible defaults.
func Load() (*Config, error) {
	cfg := &Config{
		Env:                getEnv("APP_ENV", "development"),
		Debug:              getEnvBool("APP_DEBUG", true),
		Host:               getEnv("WORLD_HOST", "0.0.0.0"),
		Port:               getEnvInt("WORLD_PORT", 8081),
		LogLevel:           getEnv("WORLD_LOG_LEVEL", "info"),
		LogPath:            getEnv("WORLD_LOG_PATH", "apps/world/logs/world.log"),
		TickMS:             getEnvInt("WORLD_TICK_MS", 100),
		RedisHost:          getEnv("REDIS_HOST", "127.0.0.1"),
		RedisPort:          getEnvInt("REDIS_PORT", 6379),
		RedisPassword:      getEnv("REDIS_PASSWORD", ""),
		MySQLHost:          getEnv("MYSQL_HOST", "127.0.0.1"),
		MySQLPort:          getEnvInt("MYSQL_PORT", 3306),
		MySQLDatabase:      getEnv("MYSQL_DATABASE", "rofs"),
		MySQLUser:          getEnv("MYSQL_USER", "rofs"),
		MySQLPassword:      getEnv("MYSQL_PASSWORD", ""),
		WSTicketTTLSeconds: getEnvInt("WS_TICKET_TTL_SECONDS", 60),
	}

	if cfg.Port < 1 || cfg.Port > 65535 {
		return nil, fmt.Errorf("invalid WORLD_PORT: %d", cfg.Port)
	}
	if cfg.TickMS < 10 {
		return nil, fmt.Errorf("WORLD_TICK_MS must be at least 10")
	}

	return cfg, nil
}

func getEnv(key, fallback string) string {
	if v := strings.TrimSpace(os.Getenv(key)); v != "" {
		return v
	}
	return fallback
}

func getEnvInt(key string, fallback int) int {
	v := strings.TrimSpace(os.Getenv(key))
	if v == "" {
		return fallback
	}
	n, err := strconv.Atoi(v)
	if err != nil {
		return fallback
	}
	return n
}

func getEnvBool(key string, fallback bool) bool {
	v := strings.ToLower(strings.TrimSpace(os.Getenv(key)))
	switch v {
	case "1", "true", "yes", "on":
		return true
	case "0", "false", "no", "off":
		return false
	default:
		return fallback
	}
}
