{-# LANGUAGE TypeFamilies  #-}
{-# LANGUAGE LambdaCase    #-}

module Gargantext.System.Logging.Types (
    LogLevel(..)
  , HasLogger(..)
  , MonadLogger(..)
  , parseLogLevel
  , renderLogLevel
  , prop_loglevel_roundtrip
  ) where

import Control.Monad.IO.Class
import Data.Kind (Type)
import Data.Text qualified as T
import Prelude


data LogLevel =
  -- | Debug messages
    DEBUG
  -- | Information
  | INFO
  -- | Normal runtime conditions
  | WARNING
  -- | General Errors
  | ERROR
  deriving (Show, Eq, Ord, Enum, Bounded, Read)

renderLogLevel :: LogLevel -> T.Text
renderLogLevel = \case
  DEBUG   -> "debug"
  INFO    -> "info"
  WARNING -> "warning"
  ERROR   -> "error"

parseLogLevel :: T.Text -> Either T.Text LogLevel
parseLogLevel = \case
  "debug"   -> Right DEBUG
  "info"    -> Right INFO
  "warning" -> Right WARNING
  "warn"    -> Right WARNING
  "error"   -> Right ERROR
  xs -> Left ("Invalid log level found: " <> xs)

prop_loglevel_roundtrip :: LogLevel -> Bool
prop_loglevel_roundtrip ll = (parseLogLevel . renderLogLevel $ ll) == Right ll

-- | This is a barebore logging interface which we
-- can extend to plug a proper logging library, without
-- the details of the logger cropping up everywhere in
-- the rest of the codebase.
class HasLogger m where
  data family Logger m        :: Type
  type family LogInitParams m :: Type
  type family LogPayload m    :: Type
  initLogger    :: LogInitParams m -> (forall m1. MonadIO m1 => m1 (Logger m))
  destroyLogger :: Logger m        -> (forall m1. MonadIO m1 => m1 ())
  logMsg        :: Logger m        -> LogLevel -> LogPayload m -> m ()
  logTxt        :: Logger m        -> LogLevel -> T.Text -> m ()

-- | Separate typeclass to get hold of a 'Logger' from within a monad.
-- We keey 'HasLogger' and 'MonadLogger' separate to enforce compositionality,
-- i.e. we can still give instances to 'HasLogger' for things like 'IO' without
-- having to force actually acquiring a logger for those monads.
class HasLogger m => MonadLogger m where
  getLogger :: m (Logger m)
