-- | This function allocates resources (such as a database connection pool),
-- performs initialization and return a foundation datatype value. This is also
-- the place to put your migrate statements to have automatic database
-- migrations handled by Yesod.
makeFoundation :: AppSettings -> IO App
makeFoundation appSettings = do
    dbconf <- if appDatabaseUrl appSettings
        then postgresConf $ pgPoolSize $ appDatabaseConf appSettings
        else return $ appDatabaseConf appSettings

    -- Some basic initializations: HTTP connection manager, logger, and static
    -- subsite.
    appHttpManager <- newManager
    appLogger <- newStdoutLoggerSet defaultBufSize >>= makeYesodLogger
    appStatic <-
        (if appMutableStatic appSettings then staticDevel else static)
        (appStaticDir appSettings)
    appGithubOAuthKeys <- getOAuthKeys "GITHUB"
    appGoogleOAuthKeys <- getOAuthKeys "GOOGLE"
    appStripeKeys <- getStripeKeys

    -- We need a log function to create a connection pool. We need a connection
    -- pool to create our foundation. And we need our foundation to get a
    -- logging function. To get out of this loop, we initially create a
    -- temporary foundation without a real connection pool, get a log function
    -- from there, and then create the real foundation.
    let mkFoundation appConnPool = App {..}
        tempFoundation = mkFoundation $ error "connPool forced in tempFoundation"
        logFunc = messageLoggerSource tempFoundation appLogger

    -- Create the database connection pool
    pool <- flip runLoggingT logFunc $ createPostgresqlPool
        (pgConnStr dbconf)
        (pgPoolSize dbconf)

    -- Perform database migration using our application's logging settings.
    runLoggingT (runSqlPool (runMigration migrateAll) pool) logFunc

    -- Return the foundation
    return $ mkFoundation pool

  where
    getOAuthKeys :: String -> IO OAuthKeys
    getOAuthKeys plugin = OAuthKeys
        <$> getEnvText (plugin ++ "_OAUTH_CLIENT_ID")
        <*> getEnvText (plugin ++ "_OAUTH_CLIENT_SECRET")

    getStripeKeys :: IO StripeKeys
    getStripeKeys = StripeKeys
        <$> getEnvText "STRIPE_SECRET_KEY"
        <*> getEnvText "STRIPE_PUBLISHABLE_KEY"

    getEnvText :: String -> IO Text
    getEnvText = fmap pack . getEnv

-- | Convert our foundation to a WAI Application by calling @toWaiAppPlain@ and
-- applyng some additional middlewares.
makeFoundation :: AppSettings -> IO App
makeFoundation appSettings = do
    dbconf <- if appDatabaseUrl appSettings
        then postgresConf $ pgPoolSize $ appDatabaseConf appSettings
        else return $ appDatabaseConf appSettings

    -- Some basic initializations: HTTP connection manager, logger, and static
    -- subsite.
    appHttpManager <- newManager
    appLogger <- newStdoutLoggerSet defaultBufSize >>= makeYesodLogger
    appStatic <-
        (if appMutableStatic appSettings then staticDevel else static)
        (appStaticDir appSettings)
    appGithubOAuthKeys <- getOAuthKeys "GITHUB"
    appGoogleOAuthKeys <- getOAuthKeys "GOOGLE"
    appStripeKeys <- getStripeKeys

    -- We need a log function to create a connection pool. We need a connection
    -- pool to create our foundation. And we need our foundation to get a
    -- logging function. To get out of this loop, we initially create a
    -- temporary foundation without a real connection pool, get a log function
    -- from there, and then create the real foundation.
    let mkFoundation appConnPool = App {..}
        tempFoundation = mkFoundation $ error "connPool forced in tempFoundation"
        logFunc = messageLoggerSource tempFoundation appLogger

    -- Create the database connection pool
    pool <- flip runLoggingT logFunc $ createPostgresqlPool
        (pgConnStr dbconf)
        (pgPoolSize dbconf)

    -- Perform database migration using our application's logging settings.
    runLoggingT (runSqlPool (runMigration migrateAll) pool) logFunc

    -- Return the foundation
    return $ mkFoundation pool

  where
    getOAuthKeys :: String -> IO OAuthKeys
    getOAuthKeys plugin = OAuthKeys
        <$> getEnvText (plugin ++ "_OAUTH_CLIENT_ID")
        <*> getEnvText (plugin ++ "_OAUTH_CLIENT_SECRET")

    getStripeKeys :: IO StripeKeys
    getStripeKeys = StripeKeys
        <$> getEnvText "STRIPE_SECRET_KEY"
        <*> getEnvText "STRIPE_PUBLISHABLE_KEY"

    getEnvText :: String -> IO Text
    getEnvText = fmap pack . getEnv

-- | Convert our foundation to a WAI Application by calling @toWaiAppPlain@ and
-- applyng some additional middlewares.
makeFoundation appSettings = do
    dbconf <- if appDatabaseUrl appSettings
        then postgresConf $ pgPoolSize $ appDatabaseConf appSettings
        else return $ appDatabaseConf appSettings

    -- Some basic initializations: HTTP connection manager, logger, and static
    -- subsite.
    appHttpManager <- newManager
    appLogger <- newStdoutLoggerSet defaultBufSize >>= makeYesodLogger
    appStatic <-
        (if appMutableStatic appSettings then staticDevel else static)
        (appStaticDir appSettings)
    appGithubOAuthKeys <- getOAuthKeys "GITHUB"
    appGoogleOAuthKeys <- getOAuthKeys "GOOGLE"
    appStripeKeys <- getStripeKeys

    -- We need a log function to create a connection pool. We need a connection
    -- pool to create our foundation. And we need our foundation to get a
    -- logging function. To get out of this loop, we initially create a
    -- temporary foundation without a real connection pool, get a log function
    -- from there, and then create the real foundation.
    let mkFoundation appConnPool = App {..}
        tempFoundation = mkFoundation $ error "connPool forced in tempFoundation"
        logFunc = messageLoggerSource tempFoundation appLogger

    -- Create the database connection pool
    pool <- flip runLoggingT logFunc $ createPostgresqlPool
        (pgConnStr dbconf)
        (pgPoolSize dbconf)

    -- Perform database migration using our application's logging settings.
    runLoggingT (runSqlPool (runMigration migrateAll) pool) logFunc

    -- Return the foundation
    return $ mkFoundation pool

  where
    getOAuthKeys :: String -> IO OAuthKeys
    getOAuthKeys plugin = OAuthKeys
        <$> getEnvText (plugin ++ "_OAUTH_CLIENT_ID")
        <*> getEnvText (plugin ++ "_OAUTH_CLIENT_SECRET")

    getStripeKeys :: IO StripeKeys
    getStripeKeys = StripeKeys
        <$> getEnvText "STRIPE_SECRET_KEY"
        <*> getEnvText "STRIPE_PUBLISHABLE_KEY"

    getEnvText :: String -> IO Text
    getEnvText = fmap pack . getEnv

-- | Convert our foundation to a WAI Application by calling @toWaiAppPlain@ and
-- applyng some additional middlewares.