{-# LANGUAGE OverloadedStrings #-}
{-|
    Module: Web.OIDC.Client.Internal
    Maintainer: krdlab@gmail.com
    Stability: experimental
-}
module Web.OIDC.Client.Internal where

import           Control.Applicative   ((<|>))
import           Control.Monad         (mzero)
import           Control.Monad.Catch   (MonadCatch, MonadThrow, throwM)
import           Data.Aeson            (FromJSON, Value (..), parseJSON, (.:),
                                        (.:?))
import           Data.Aeson.Types      (Parser)
import           Data.Text             (Text, unpack)
import           Data.Text.Read        (decimal)
import           Jose.Jwt              (Jwt)
import           Network.HTTP.Client   (HttpException, Request, parseRequest)
import           Prelude               hiding (exp)
import           Web.OIDC.Client.Types (OpenIdException (InternalHttpException))

data TokensResponse = TokensResponse
    { accessToken  :: !Text
    , tokenType    :: !Text
    , idToken      :: !Jwt
    , expiresIn    :: !(Maybe Integer)
    , refreshToken :: !(Maybe Text)
    }
  deriving (Show, Eq)

instance FromJSON TokensResponse where
    parseJSON (Object o) = TokensResponse
        <$>  o .:  "access_token"
        <*>  o .:  "token_type"
        <*>  o .:  "id_token"
        <*> ((o .:? "expires_in") <|> (textToInt =<< (o .:? "expires_in")))
        <*>  o .:? "refresh_token"
    parseJSON _          = mzero

textToInt :: Maybe Text -> Parser (Maybe Integer)
textToInt (Just t) =
    case decimal t of
        Right (i, _) -> pure $ Just i
        Left  _      -> fail "expires_in: expected a decimal text, encountered a non decimal text"
textToInt _        = pure Nothing

rethrow :: (MonadCatch m) => HttpException -> m a
rethrow = throwM . InternalHttpException

parseUrl :: MonadThrow m => Text -> m Request
parseUrl = Network.HTTP.Client.parseRequest . unpack