-- |
-- Module      :  Configuration.Dotenv.Types
-- Copyright   :  © 2015–2020 Stack Builders Inc.
-- License     :  MIT
--
-- Maintainer  :  Stack Builders <hackage@stackbuilders.com>
-- Stability   :  experimental
-- Portability :  portable
--
-- Types for 'loadSafeFile' (e. g., 'ValidatorMap')

{-# LANGUAGE CPP               #-}
{-# LANGUAGE OverloadedStrings #-}

module Configuration.Dotenv.Scheme.Types where

#if !MIN_VERSION_base(4,8,0)
import           Control.Applicative (pure, (<*>))
import           Data.Functor        ((<$>))
#endif

import           Data.Maybe          (isJust)

import           Data.Map.Lazy       (Map)

import           Data.Yaml

import qualified Data.Map.Lazy       as ML

import           Data.Text           (Text)
import qualified Data.Text           as T

import           Text.Read           (readMaybe)


-- |
--
newtype EnvType = EnvType Text
    deriving (Show, Eq, Ord)

-- |
--
instance FromJSON EnvType where
  parseJSON (String value) = pure (EnvType value)
  parseJSON anyOther       = fail ("Not an object: " ++ show anyOther)

-- |
--
data Env =
  Env
    { envName  :: String
    , envType  :: EnvType
    , required :: Bool
    } deriving (Show, Eq, Ord)

-- |
--
instance FromJSON Env where
  parseJSON (Object m) =
    Env
      <$> m .: "name"
      <*> m .: "type"
      <*> m .:? "required" .!= False
  parseJSON x = fail ("Not an object: " ++ show x)

-- | Parameters:
--
-- - __Key:__ Name of the /format/ to check.
--
-- - __Value:__ Function to check if some text meets the condition.
--
type ValidatorMap = Map Text (Text -> Bool)


-- | Default configuration for 'loadSafeFile'. It currently checks:
-- @bool@, @integer@, and @text@.
--
defaultValidatorMap :: ValidatorMap
defaultValidatorMap =
  let booleanValidator :: Text -> Bool
      booleanValidator text = isJust (readMaybe (T.unpack text) :: Maybe Bool)
      integerValidator :: Text -> Bool
      integerValidator text = isJust (readMaybe (T.unpack text) :: Maybe Integer)
      textValidator :: Text -> Bool
      textValidator = const True
   in ML.fromList
        [ ("bool", booleanValidator)
        , ("integer", integerValidator)
        , ("text", textValidator)
        ]