// Package env provides typed helpers for reading environment variables.
//
// All functions treat an unset variable and an empty string as distinct only
// when explicitly documented: Must/Get distinguish "not set" from "set to empty"
// via os.LookupEnv, while GetInt/GetBool/GetDuration fall back to the default
// value when parsing fails.
package env

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

// Must returns the value of the environment variable named by key.
// It panics if the variable is not set, which is intended for values that the
// service cannot start without (DB URLs, JWT secrets, ...).
func Must(key string) string {
	v, ok := os.LookupEnv(key)
	if !ok {
		panic(fmt.Sprintf("env: required environment variable %q is not set", key))
	}
	return v
}

// Get returns the value of the environment variable named by key, or
// defaultValue when the variable is not set.
func Get(key, defaultValue string) string {
	if v, ok := os.LookupEnv(key); ok {
		return v
	}
	return defaultValue
}

// GetInt returns the integer value of the environment variable named by key,
// or defaultValue when the variable is not set or cannot be parsed as an int.
func GetInt(key string, defaultValue int) int {
	if v, ok := os.LookupEnv(key); ok {
		n, err := strconv.Atoi(v)
		if err != nil {
			return defaultValue
		}
		return n
	}
	return defaultValue
}

// GetBool returns the boolean value of the environment variable named by key,
// or defaultValue when the variable is not set or cannot be parsed as a bool
// (accepted values are those understood by strconv.ParseBool: 1, t, T, TRUE,
// true, True, 0, f, F, FALSE, false, False).
func GetBool(key string, defaultValue bool) bool {
	if v, ok := os.LookupEnv(key); ok {
		b, err := strconv.ParseBool(v)
		if err != nil {
			return defaultValue
		}
		return b
	}
	return defaultValue
}

// GetDuration returns the duration value of the environment variable named by
// key, or defaultValue when the variable is not set or cannot be parsed by
// time.ParseDuration (e.g. "30s", "5m", "2h").
func GetDuration(key string, defaultValue time.Duration) time.Duration {
	if v, ok := os.LookupEnv(key); ok {
		d, err := time.ParseDuration(v)
		if err != nil {
			return defaultValue
		}
		return d
	}
	return defaultValue
}
