{-# LANGUAGE ConstraintKinds #-}
{-|
Module: IHP.FrameworkConfig.Types
Description: Core types for framework configuration
Copyright: (c) digitally induced GmbH, 2020

This module contains the core types for IHP's framework configuration.
It's designed to be lightweight and avoid Template Haskell dependencies,
allowing modules that only need the types to compile faster.

For the full configuration API including defaults, use 'IHP.FrameworkConfig'.
-}
module IHP.FrameworkConfig.Types
( AppHostname (..)
, AppPort (..)
, BaseUrl (..)
, RequestLoggerMiddleware (..)
, SessionCookie (..)
, DatabaseUrl (..)
, ConfigBuilder
, ExceptionTracker (..)
, IdeBaseUrl (..)
, RLSAuthenticatedRole (..)
, AssetVersion (..)
, CustomMiddleware (..)
, DataSyncMaxSubscriptionsPerConnection (..)
, DataSyncMaxTransactionsPerConnection (..)
, Initializer (..)
, FrameworkConfig (..)
, ConfigProvider
) where

import Prelude
import Data.ByteString (ByteString)
import Data.Text (Text)
import Control.Exception (SomeException)
import GHC.Records (HasField(..))
import qualified Control.Monad.Trans.State.Strict as State
import qualified Data.TMap as TMap
import qualified Web.Cookie as Cookie
import qualified Network.Wai.Middleware.Cors as Cors
import qualified Network.Wai.Parse as WaiParse
import Network.Wai (Middleware, Request)
import IHP.Environment (Environment)
import IHP.View.Types (CSSFramework)
import IHP.Log.Types (Logger)
import IHP.ModelSupport.Types (ModelContext)

newtype AppHostname = AppHostname Text
newtype AppPort = AppPort Int
newtype BaseUrl = BaseUrl Text

-- | Provides IHP with a middleware to log requests and responses.
--
-- By default this uses the RequestLogger middleware from wai-extra. Take a look at the wai-extra
-- documentation when you want to customize the request logging.
--
-- See https://hackage.haskell.org/package/wai-extra-3.0.29.2/docs/Network-Wai-Middleware-RequestLogger.html
--
--
-- Set @requestLoggerMiddleware = \application -> application@ to disable request logging.
newtype RequestLoggerMiddleware = RequestLoggerMiddleware Middleware

-- | Provides the default settings for the session cookie.
--
-- - Max Age: 30 days
-- - Same Site Policy: Lax
-- - HttpOnly (no access through JS)
-- - secure, when baseUrl is a https url
--
-- Override this to set e.g. a custom max age or change the default same site policy.
--
-- __Example: Set max age to 90 days__
-- > sessionCookie = defaultIHPSessionCookie { Cookie.setCookieMaxAge = Just (fromIntegral (60 * 60 * 24 * 90)) }
newtype SessionCookie = SessionCookie Cookie.SetCookie

newtype DatabaseUrl = DatabaseUrl ByteString

type ConfigBuilder = State.StateT TMap.TMap IO ()

-- | Interface for exception tracking services such as sentry
newtype ExceptionTracker = ExceptionTracker { ExceptionTracker -> Maybe Request -> SomeException -> IO ()
onException :: Maybe Request -> SomeException -> IO () }

-- | Typically "http://localhost:8001", Url where the IDE is running
newtype IdeBaseUrl = IdeBaseUrl Text

-- | Postgres role to be used for making queries with Row level security enabled
newtype RLSAuthenticatedRole = RLSAuthenticatedRole Text

newtype AssetVersion = AssetVersion Text

newtype CustomMiddleware = CustomMiddleware Middleware

newtype DataSyncMaxSubscriptionsPerConnection = DataSyncMaxSubscriptionsPerConnection Int
newtype DataSyncMaxTransactionsPerConnection = DataSyncMaxTransactionsPerConnection Int

newtype Initializer = Initializer { Initializer
-> (?context::FrameworkConfig, ?modelContext::ModelContext) =>
   IO ()
onStartup :: (?context :: FrameworkConfig, ?modelContext :: ModelContext) => IO () }

data FrameworkConfig = FrameworkConfig
    { FrameworkConfig -> Text
appHostname :: !Text
    , FrameworkConfig -> Environment
environment :: !Environment
    , FrameworkConfig -> Int
appPort :: !Int
    , FrameworkConfig -> Text
baseUrl :: !Text

    -- | Provides IHP with a middleware to log requests and responses.
    --
    -- By default this uses the RequestLogger middleware from wai-extra. Take a look at the wai-extra
    -- documentation when you want to customize the request logging.
    --
    -- See https://hackage.haskell.org/package/wai-extra-3.0.29.2/docs/Network-Wai-Middleware-RequestLogger.html
    --
    --
    -- Set @requestLoggerMiddleware = \application -> application@ to disable request logging.
    , FrameworkConfig -> Middleware
requestLoggerMiddleware :: !Middleware

    -- | Provides the default settings for the session cookie.
    --
    -- - Max Age: 30 days
    -- - Same Site Policy: Lax
    -- - HttpOnly (no access through JS)
    -- - secure, when baseUrl is a https url
    --
    -- Override this to set e.g. a custom max age or change the default same site policy.
    --
    -- __Example: Set max age to 90 days__
    -- > sessionCookie = defaultIHPSessionCookie { Cookie.setCookieMaxAge = Just (fromIntegral (60 * 60 * 24 * 90)) }
    , FrameworkConfig -> SetCookie
sessionCookie :: !Cookie.SetCookie

    , FrameworkConfig -> ByteString
databaseUrl :: !ByteString

    -- | Bootstrap 4 by default
    --
    -- Override this if you use a CSS framework that is not bootstrap
    , FrameworkConfig -> CSSFramework
cssFramework :: !CSSFramework
    , FrameworkConfig -> Logger
logger :: !Logger
    , FrameworkConfig -> ExceptionTracker
exceptionTracker :: !ExceptionTracker

    -- | Custom 'option's from @Config.hs@ are stored here
    , FrameworkConfig -> TMap
appConfig :: !TMap.TMap

    -- | Configures CORS headers for the application
    , FrameworkConfig -> Maybe CorsResourcePolicy
corsResourcePolicy :: !(Maybe Cors.CorsResourcePolicy)

    -- | Configures the limits for request parameters, uploaded files, maximum number of headers etc.
    , FrameworkConfig -> ParseRequestBodyOptions
parseRequestBodyOptions :: !WaiParse.ParseRequestBodyOptions

    -- | Used by the dev server. This field cannot be strict.
    , FrameworkConfig -> Text
ideBaseUrl :: Text

    -- | See IHP.DataSync.Role
    , FrameworkConfig -> Text
rlsAuthenticatedRole :: !Text

    -- | User provided WAI middleware that is run after IHP's middleware stack.
    , FrameworkConfig -> CustomMiddleware
customMiddleware :: !CustomMiddleware
    , FrameworkConfig -> [Initializer]
initializers :: ![Initializer]
    }

instance HasField "frameworkConfig" FrameworkConfig FrameworkConfig where
    getField :: FrameworkConfig -> FrameworkConfig
getField FrameworkConfig
frameworkConfig = FrameworkConfig
frameworkConfig

type ConfigProvider context = HasField "frameworkConfig" context FrameworkConfig