defmodule SignificaUtils.ConfigUtils do @moduledoc """ Utility functions for configuration parsing and environment variable handling. """ @doc """ Retrieves an environment variable. The default value is used either when the variable does not exist or is empty. ## Examples iex> System.put_env("TEST_ENV_VAR_GET_ENV_1", "sample_value") iex> ConfigUtils.get_env("TEST_ENV_VAR_GET_ENV_1") "sample_value" iex> System.put_env("TEST_ENV_VAR_GET_ENV_2", "") iex> ConfigUtils.get_env("TEST_ENV_VAR_GET_ENV_2") nil iex> System.put_env("TEST_ENV_VAR_GET_ENV_3", "") iex> ConfigUtils.get_env("TEST_ENV_VAR_GET_ENV_3", "sample-default-value") "sample-default-value" iex> ConfigUtils.get_env("NONEXISTENT_VAR") nil iex> ConfigUtils.get_env("NONEXISTENT_VAR", "sample-default-value") "sample-default-value" """ def get_env(env_name, default \\ nil) do case System.get_env(env_name) do nil -> default "" -> default value -> value end end @doc """ Fetches an environment variable and raises an error if it's not set or it is empty. ## Examples iex> System.put_env("TEST_ENV_VAR_FETCH_ENV_1", "sample_value") iex> ConfigUtils.fetch_env("TEST_ENV_VAR_FETCH_ENV_1") "sample_value" iex> System.put_env("TEST_ENV_VAR_FETCH_ENV_2", "") iex> ConfigUtils.fetch_env("TEST_ENV_VAR_FETCH_ENV_2") ** (RuntimeError) Environment variable 'TEST_ENV_VAR_FETCH_ENV_2' must not be empty iex> ConfigUtils.fetch_env("NONEXISTENT_VAR") ** (RuntimeError) Environment variable 'NONEXISTENT_VAR' must be set """ def fetch_env(env_name) do case System.get_env(env_name) do nil -> raise "Environment variable '#{env_name}' must be set" "" -> raise "Environment variable '#{env_name}' must not be empty" value -> value end end @doc """ Parses an email recipient string in the format "Sample Recipient ". Returns a tuple `{name, email}` or `nil` if the input is `nil`. ## Examples iex> ConfigUtils.parse_email_recipient("John Doe ") {"John Doe", "john@example.com"} iex> ConfigUtils.parse_email_recipient(nil) nil iex> ConfigUtils.parse_email_recipient("admin ") {"admin", "admin@company.org"} iex> ConfigUtils.parse_email_recipient("invalid format") ** (RuntimeError) Invalid email recipient format. Expected 'Name ', received: "invalid format" """ def parse_email_recipient(nil), do: nil def parse_email_recipient(email_recipient) do case Regex.run(~r/^(.+?)\s*<(.+?)>$/, email_recipient) do [_, name, email] -> {String.trim(name), email} nil -> raise "Invalid email recipient format. Expected 'Name ', received: #{inspect(email_recipient)}" end end @doc """ Parses an ISO 8601 datetime string and raises an error if it is invalid or no in in UTC timezone. ## Examples iex> ConfigUtils.parse_datetime("2025-07-17T00:00:00Z") ~U[2025-07-17 00:00:00Z] iex> ConfigUtils.parse_datetime("2025-07-17T00:00:00+00:00") ~U[2025-07-17 00:00:00Z] iex> ConfigUtils.parse_datetime("2025-07-17T00:00:00+01:00") ** (RuntimeError) Error parsing datetime, configs must be provided via ISO Datetime in UTC timezone. Received: "2025-07-17T00:00:00+01:00" """ def parse_datetime(iso_datetime_string) do case DateTime.from_iso8601(iso_datetime_string) do {:ok, datetime, 0} -> datetime _ -> raise "Error parsing datetime, configs must be provided via ISO Datetime in UTC timezone. " <> "Received: #{inspect(iso_datetime_string)}" end end end