package main

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

type Config struct {
	AppEnv      string // dev, staging, prod
	Port        int
	DatabaseDSN string
	APIToken    string // rahasia: jangan pernah dicetak mentah
}

func Muat() (Config, error) {
	cfg := Config{
		AppEnv:      ambil("APP_ENV", "dev"),
		Port:        8080,
		DatabaseDSN: ambil("DATABASE_DSN", "postgres://app@localhost/app_dev"),
		APIToken:    os.Getenv("API_TOKEN"),
	}
	if v := os.Getenv("PORT"); v != "" {
		n, err := strconv.Atoi(v)
		if err != nil {
			return Config{}, fmt.Errorf("PORT harus angka, dapat %q", v)
		}
		cfg.Port = n
	}

	// validasi fail-fast: salah konfigurasi sebaiknya gagal saat start.
	switch cfg.AppEnv {
	case "dev", "staging", "prod":
	default:
		return Config{}, fmt.Errorf("APP_ENV tidak valid: %q (harus dev/staging/prod)", cfg.AppEnv)
	}
	if cfg.AppEnv == "prod" && cfg.APIToken == "" {
		return Config{}, fmt.Errorf("API_TOKEN wajib diisi di lingkungan prod")
	}
	return cfg, nil
}

func ambil(kunci, cadangan string) string {
	if v := os.Getenv(kunci); v != "" {
		return v
	}
	return cadangan
}

func (c Config) Redacted() string {
	return fmt.Sprintf("AppEnv=%s Port=%d DatabaseDSN=%s APIToken=%s",
		c.AppEnv, c.Port, c.DatabaseDSN, tutup(c.APIToken))
}

func tutup(rahasia string) string {
	if rahasia == "" {
		return "(kosong)"
	}
	return strings.Repeat("*", 8)
}

func main() {
	// mensimulasikan environment yang diatur oleh sistem operasi/CI.
	os.Setenv("APP_ENV", "prod")
	os.Setenv("PORT", "9090")
	os.Setenv("API_TOKEN", "YOUR_API_TOKEN")

	cfg, err := Muat()
	if err != nil {
		fmt.Println("gagal memuat konfigurasi:", err)
		os.Exit(1)
	}
	fmt.Println("konfigurasi:", cfg.Redacted())

	// fail-fast: token hilang di prod harus tertangkap saat start.
	os.Unsetenv("API_TOKEN")
	_, err = Muat()
	fmt.Println("muat ulang tanpa token:", err)
}
