{-#LANGUAGE NoImplicitPrelude #-}
{-#LANGUAGE OverloadedStrings #-}
{-#LANGUAGE OverloadedLists #-}
{-#LANGUAGE LambdaCase #-}
{-#LANGUAGE ScopedTypeVariables #-}
{-#LANGUAGE FlexibleInstances #-}
{-#LANGUAGE FlexibleContexts #-}
{-#LANGUAGE MultiParamTypeClasses #-}
{-#LANGUAGE TypeApplications #-}
module Web.Sprinkles.SessionHandle
( SessionHandle (..)
, makeSessionHandle
)
where

import Web.Sprinkles.Prelude
import Web.Sprinkles.SessionStore
import Text.Ginger
       (GVal(..), ToGVal(..),
        (~>))
import qualified Text.Ginger as Ginger
import Data.Default

data SessionHandle =
    SessionHandle
        { sessionID :: SessionID
        , sessionGet :: Text -> IO (Maybe Text)
        , sessionPut :: Text -> Text -> IO ()
        }

instance (Monad m, MonadIO m) => ToGVal (Ginger.Run p m h) SessionHandle where
    toGVal session =
        Ginger.dict
            [ "id" ~> decodeUtf8 @Text (sessionID session)
            , ("get", Ginger.fromFunction (gSessionGet $ session))
            , ("put", Ginger.fromFunction (gSessionPut $ session))
            ]

gSessionGet :: (Monad m, MonadIO m) => SessionHandle -> Ginger.Function (Ginger.Run p m h)
gSessionGet session args = do
    let (matched, position, named) = Ginger.matchFuncArgs ["key"] args
    case lookup "key" matched of
        Nothing ->
            return def
        Just key -> do
            toGVal <$> liftIO (sessionGet session $ Ginger.asText key)

gSessionPut :: (Monad m, MonadIO m) => SessionHandle -> Ginger.Function (Ginger.Run p m h)
gSessionPut session args = do
    let (matched, position, named) = Ginger.matchFuncArgs ["key", "value"] args
    case lookup "key" matched of
        Nothing ->
            return def
        Just key -> do
            liftIO $ sessionPut session
                (Ginger.asText key)
                (Ginger.asText . fromMaybe def $ lookup "value" matched)
            return def

makeSessionHandle :: SessionStore -> SessionID -> SessionHandle
makeSessionHandle ss ssid =
    SessionHandle
        { sessionID = ssid
        , sessionGet = ssGet ss ssid
        , sessionPut = ssPut ss ssid
        }