package main

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

type Config struct {
	DatabaseURL string

	APIURL    string
	APISecret string

	DockerHost      string
	GameserverImage string

	PublicHost     string
	PortRangeStart int
	PortRangeEnd   int

	GSLTTokens []string

	ProvisionInterval   time.Duration
	HealthCheckInterval time.Duration
	CleanupInterval     time.Duration
	MaxBootWait         time.Duration
	MaxMatchDuration    time.Duration

	GameserverNetwork string

	DemoMode bool
}

func LoadConfig() (*Config, error) {
	cfg := &Config{}

	cfg.DatabaseURL = os.Getenv("DATABASE_URL")
	if cfg.DatabaseURL == "" {
		return nil, fmt.Errorf("DATABASE_URL environment variable is required")
	}

	cfg.APIURL = envOrDefault("API_URL", "http://api-1:3000")
	cfg.APISecret = os.Getenv("API_SECRET")
	if cfg.APISecret == "" {
		return nil, fmt.Errorf("API_SECRET environment variable is required")
	}

	cfg.DockerHost = envOrDefault("DOCKER_HOST", "")
	cfg.GameserverImage = envOrDefault("GAMESERVER_IMAGE", "tapper-gameserver")

	cfg.PublicHost = envOrDefault("PUBLIC_HOST", "localhost")
	cfg.GameserverNetwork = envOrDefault("GAMESERVER_NETWORK", "tapper-gameservers")

	var err error
	cfg.PortRangeStart, err = envOrDefaultInt("PORT_RANGE_START", 27015)
	if err != nil {
		return nil, fmt.Errorf("invalid PORT_RANGE_START: %w", err)
	}
	cfg.PortRangeEnd, err = envOrDefaultInt("PORT_RANGE_END", 27064)
	if err != nil {
		return nil, fmt.Errorf("invalid PORT_RANGE_END: %w", err)
	}
	if cfg.PortRangeStart >= cfg.PortRangeEnd {
		return nil, fmt.Errorf("PORT_RANGE_START (%d) must be less than PORT_RANGE_END (%d)", cfg.PortRangeStart, cfg.PortRangeEnd)
	}

	gsltRaw := os.Getenv("GSLT_TOKENS")
	if gsltRaw != "" {
		for _, token := range strings.Split(gsltRaw, ",") {
			token = strings.TrimSpace(token)
			if token != "" {
				cfg.GSLTTokens = append(cfg.GSLTTokens, token)
			}
		}
	}

	cfg.ProvisionInterval = envOrDefaultDuration("PROVISION_INTERVAL", 2*time.Second)
	cfg.HealthCheckInterval = envOrDefaultDuration("HEALTH_CHECK_INTERVAL", 5*time.Second)
	cfg.CleanupInterval = envOrDefaultDuration("CLEANUP_INTERVAL", 30*time.Second)
	cfg.MaxBootWait = envOrDefaultDuration("MAX_BOOT_WAIT", 120*time.Second)
	cfg.MaxMatchDuration = envOrDefaultDuration("MAX_MATCH_DURATION", 90*time.Minute)

	cfg.DemoMode = strings.EqualFold(envOrDefault("DEMO_MODE", "false"), "true")

	return cfg, nil
}

func envOrDefault(key, fallback string) string {
	if v := os.Getenv(key); v != "" {
		return v
	}
	return fallback
}

func envOrDefaultInt(key string, fallback int) (int, error) {
	v := os.Getenv(key)
	if v == "" {
		return fallback, nil
	}
	return strconv.Atoi(v)
}

func envOrDefaultDuration(key string, fallback time.Duration) time.Duration {
	v := os.Getenv(key)
	if v == "" {
		return fallback
	}
	d, err := time.ParseDuration(v)
	if err != nil {
		return fallback
	}
	return d
}
