package config

import (
	"fmt"
	"os"
	"strconv"
)

type Config struct {
	// Server
	Port string

	// Database
	DatabaseURL string

	// Storage
	RepoRoot string

	// Security
	SessionSecret string // must be 32 or 64 bytes for AES-GCM
	CSRFSecret    string // must be 32 bytes

	// OIDC (optional)
	OIDCIssuer       string
	OIDCClientID     string
	OIDCClientSecret string

	// Federation
	InstanceURL  string
	InstanceName string

	// Dev
	Debug bool
}

func Load() (*Config, error) {
	cfg := &Config{
		Port:     getEnv("PORT", "8080"),
		RepoRoot: getEnv("REPO_ROOT", "/var/lib/forgebucket/repos"),
		Debug:    getEnvBool("DEBUG", false),

		InstanceURL:  getEnv("INSTANCE_URL", ""),
		InstanceName: getEnv("INSTANCE_NAME", "ForgeBucket"),
	}

	var missing []string

	cfg.DatabaseURL = requireEnv("DATABASE_URL", &missing)
	cfg.SessionSecret = requireEnv("SESSION_SECRET", &missing)
	cfg.CSRFSecret = requireEnv("CSRF_SECRET", &missing)

	// Optional OIDC
	cfg.OIDCIssuer = os.Getenv("OIDC_ISSUER")
	cfg.OIDCClientID = os.Getenv("OIDC_CLIENT_ID")
	cfg.OIDCClientSecret = os.Getenv("OIDC_CLIENT_SECRET")

	if len(missing) > 0 {
		return nil, fmt.Errorf("missing required env vars: %v", missing)
	}

	if len(cfg.SessionSecret) < 32 {
		return nil, fmt.Errorf("SESSION_SECRET must be at least 32 characters")
	}
	if len(cfg.CSRFSecret) != 32 {
		return nil, fmt.Errorf("CSRF_SECRET must be exactly 32 characters")
	}

	return cfg, nil
}

func requireEnv(key string, missing *[]string) string {
	v := os.Getenv(key)
	if v == "" {
		*missing = append(*missing, key)
	}
	return v
}

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

func getEnvBool(key string, fallback bool) bool {
	v := os.Getenv(key)
	if v == "" {
		return fallback
	}
	b, err := strconv.ParseBool(v)
	if err != nil {
		return fallback
	}
	return b
}
