content: {-# LANGUAGE DerivingStrategies #-}
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  
  module Keter.Context where
  
  import Control.Monad.IO.Class (MonadIO)
  import Control.Monad.IO.Unlift (MonadUnliftIO)
  import Control.Monad.Logger
         (LoggingT(..), MonadLogger, MonadLoggerIO, runLoggingT)
  import Control.Monad.Reader (MonadReader, ReaderT, withReaderT)
  
  -- | The top-level keter context monad, carrying around the main logger and some locally relevant configuration structure.
  --
  -- See this blog post for an explanation of the design philosophy: https://www.fpcomplete.com/blog/2017/06/readert-design-pattern/
  --
  -- TODO: generalize as /contexts/ instead of /configs/? Since not every state being passed
  -- around can be intuitively thought of as a config per se. Ex. AppManager
  newtype KeterM cfg a = KeterM { runKeterM :: LoggingT (ReaderT cfg IO) a }
    deriving newtype (Functor, Applicative, Monad,
                      MonadUnliftIO,
                      MonadIO, MonadLogger, MonadLoggerIO,
                      MonadReader cfg)
  
  withMappedConfig :: (cfg -> cfg') -> KeterM cfg' a -> KeterM cfg a
  withMappedConfig f (KeterM ctx) =
      KeterM $ LoggingT $ \logger -> withReaderT f $ runLoggingT ctx logger
  