module Control.Eff.Log.MessageFactory
  ( mkLogMsg
  , MessageFactory()
  , MessageFactoryReader
  , withLogMessageFactory
  , composeMessageFactories
  , localMessageFactory
  )
where

import           Control.Eff
import           Control.Eff.Log         hiding ( Severity )
import           Control.Eff.Reader.Strict
import           Control.Eff.Lift
import           Control.Monad.IO.Class
import           Data.Default

newtype MessageFactory m =
  MessageFactory { runMessageFactory :: IO m}

type MessageFactoryReader m = Reader (MessageFactory m)

mkLogMsg
  :: forall m io e
   . ( Member (Logs m) e
     , MonadIO io
     , SetMember Lift (Lift io) e
     , Member (MessageFactoryReader m) e
     )
  => (m -> m)
  -> Eff e ()
mkLogMsg f = ask >>= lift . liftIO . runMessageFactory >>= logMsg . f

localMessageFactory
  :: forall m e a
   . (Member (MessageFactoryReader m) e)
  => IO m
  -> Eff e a
  -> Eff e a
localMessageFactory = local . const . MessageFactory

composeMessageFactories
  :: forall m e a
   . (Member (MessageFactoryReader m) e)
  => (m -> IO m)
  -> Eff e a
  -> Eff e a
composeMessageFactories f2 =
  local (\(MessageFactory f1) -> MessageFactory (f1 >>= f2))

withLogMessageFactory
  :: forall m io e a
   . (Member (Logs m) e, Default m, MonadIO io, SetMember Lift (Lift io) e)
  => Eff (MessageFactoryReader m ': e) a
  -> Eff e a
withLogMessageFactory = runReader (MessageFactory (return def))