module Conferer.Source.Env
  (
-- * Env Source
-- | This 'Source' provides config values from env vars given a prefix that's
-- used to avoid colliding with different system configuration
--
-- For example if you use the 'Prefix' "awesomeapp" and get the 'Key'
-- "warp.port" this source will try to lookup the env var called
-- @AWESOMEAPP_WARP_PORT@.

-- * Usage
-- | To use this source simply choose a prefix and add it using the
-- 'addSource' function like:
--
-- @
-- config & 'addSource' ('mkEnvSource' "awesomeapp")
-- @
    mkEnvSource
    , mkEnvSource'
    , Prefix
    , LookupEnvFunc
    , keyToEnvVar
  ) where


import           Data.Text (Text)
import qualified Data.Text as Text
import qualified System.Environment as System

import           Conferer.Types

-- | 'SourceCreator' for env 'Source' that uses the real 'System.lookupEnv'
-- function
mkEnvSource :: Prefix -> SourceCreator
mkEnvSource prefix =
  mkEnvSource' System.lookupEnv prefix

-- | 'SourceCreator' for env 'Source' that allows parameterizing the
-- function used to lookup for testing
mkEnvSource' :: LookupEnvFunc -> Prefix -> SourceCreator
mkEnvSource' lookupEnv prefix = \_config ->
  return $
  Source
  { getKeyInSource = \k -> do
      let envVarName = Text.unpack $ keyToEnvVar prefix k
      fmap Text.pack <$> lookupEnv envVarName
  }

-- | Type alias for the function to lookup env vars
type LookupEnvFunc = String -> IO (Maybe String)


-- | A text to namespace env vars
type Prefix = Text

-- | Get the env name from a prefix and a key by uppercasing and
-- intercalating underscores
--
-- >>> keyToEnVar "awesomeapp" "warp.port"
-- "AWESOMEAPP_WARP_PORT"
keyToEnvVar :: Prefix -> Key -> Text
keyToEnvVar prefix (Path keys) =
  Text.toUpper
  $ Text.intercalate "_"
  $ filter (/= mempty)
  $ prefix : keys