module Bank.TrueLayer.Internal
  ( getWithAuth
  , getWithAuthAndOptions
  , postWithAuth
  , defaults
  , header
  , param
  , fromString
  , (.~)
  , (&)
  , (</>)
  , Options
  , Endpoint(..)
  , AccessToken(..)
  ) where

import           Control.Lens         ((&), (.~), (?~), (^.))
import           Data.Aeson           (FromJSON, ToJSON (..))
import           Data.String          (fromString)
import           Data.Text.Encoding   (encodeUtf8)
import           Network.OAuth.OAuth2 (AccessToken (..))
import           Network.Wreq
    (Options, asJSON, auth, defaults, getWith, header, oauth2Bearer, param, postWith, responseBody)
import           System.FilePath      ((</>))

newtype Endpoint = Endpoint String

getWithAuth :: FromJSON a => String -> Endpoint -> AccessToken -> IO (Maybe a)
getWithAuth :: forall a.
FromJSON a =>
String -> Endpoint -> AccessToken -> IO (Maybe a)
getWithAuth String
uri (Endpoint String
endpoint) (AccessToken Text
accessToken) = do
  let opts :: Options
opts = Options
defaults Options -> (Options -> Options) -> Options
forall a b. a -> (a -> b) -> b
& (Maybe Auth -> Identity (Maybe Auth))
-> Options -> Identity Options
Lens' Options (Maybe Auth)
auth ((Maybe Auth -> Identity (Maybe Auth))
 -> Options -> Identity Options)
-> Auth -> Options -> Options
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ ByteString -> Auth
oauth2Bearer (Text -> ByteString
encodeUtf8 Text
accessToken)
  Response (Maybe a)
r <- Response ByteString -> IO (Response (Maybe a))
forall (m :: * -> *) a.
(MonadThrow m, FromJSON a) =>
Response ByteString -> m (Response a)
asJSON (Response ByteString -> IO (Response (Maybe a)))
-> IO (Response ByteString) -> IO (Response (Maybe a))
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Options -> String -> IO (Response ByteString)
getWith Options
opts (String
endpoint String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
uri)
  Maybe a -> IO (Maybe a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Response (Maybe a)
r Response (Maybe a)
-> Getting (Maybe a) (Response (Maybe a)) (Maybe a) -> Maybe a
forall s a. s -> Getting a s a -> a
^. Getting (Maybe a) (Response (Maybe a)) (Maybe a)
forall body0 body1 (f :: * -> *).
Functor f =>
(body0 -> f body1) -> Response body0 -> f (Response body1)
responseBody)

getWithAuthAndOptions :: FromJSON a => Options -> String -> Endpoint -> AccessToken -> IO (Maybe a)
getWithAuthAndOptions :: forall a.
FromJSON a =>
Options -> String -> Endpoint -> AccessToken -> IO (Maybe a)
getWithAuthAndOptions Options
options String
uri (Endpoint String
endpoint) (AccessToken Text
accessToken) = do
  let opts :: Options
opts = Options
options Options -> (Options -> Options) -> Options
forall a b. a -> (a -> b) -> b
& (Maybe Auth -> Identity (Maybe Auth))
-> Options -> Identity Options
Lens' Options (Maybe Auth)
auth ((Maybe Auth -> Identity (Maybe Auth))
 -> Options -> Identity Options)
-> Auth -> Options -> Options
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ ByteString -> Auth
oauth2Bearer (Text -> ByteString
encodeUtf8 Text
accessToken)
  Response (Maybe a)
r <- Response ByteString -> IO (Response (Maybe a))
forall (m :: * -> *) a.
(MonadThrow m, FromJSON a) =>
Response ByteString -> m (Response a)
asJSON (Response ByteString -> IO (Response (Maybe a)))
-> IO (Response ByteString) -> IO (Response (Maybe a))
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Options -> String -> IO (Response ByteString)
getWith Options
opts (String
endpoint String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
uri)
  Maybe a -> IO (Maybe a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Response (Maybe a)
r Response (Maybe a)
-> Getting (Maybe a) (Response (Maybe a)) (Maybe a) -> Maybe a
forall s a. s -> Getting a s a -> a
^. Getting (Maybe a) (Response (Maybe a)) (Maybe a)
forall body0 body1 (f :: * -> *).
Functor f =>
(body0 -> f body1) -> Response body0 -> f (Response body1)
responseBody)

postWithAuth :: (ToJSON body, FromJSON res) => String -> body -> Endpoint -> AccessToken -> IO (Maybe res)
postWithAuth :: forall body res.
(ToJSON body, FromJSON res) =>
String -> body -> Endpoint -> AccessToken -> IO (Maybe res)
postWithAuth String
uri body
body (Endpoint String
endpoint) (AccessToken Text
accessToken) = do
  let opts :: Options
opts = Options
defaults Options -> (Options -> Options) -> Options
forall a b. a -> (a -> b) -> b
& (Maybe Auth -> Identity (Maybe Auth))
-> Options -> Identity Options
Lens' Options (Maybe Auth)
auth ((Maybe Auth -> Identity (Maybe Auth))
 -> Options -> Identity Options)
-> Auth -> Options -> Options
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ ByteString -> Auth
oauth2Bearer (Text -> ByteString
encodeUtf8 Text
accessToken)
  Response (Maybe res)
r <- Response ByteString -> IO (Response (Maybe res))
forall (m :: * -> *) a.
(MonadThrow m, FromJSON a) =>
Response ByteString -> m (Response a)
asJSON (Response ByteString -> IO (Response (Maybe res)))
-> IO (Response ByteString) -> IO (Response (Maybe res))
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Options -> String -> Value -> IO (Response ByteString)
forall a.
Postable a =>
Options -> String -> a -> IO (Response ByteString)
postWith Options
opts (String
endpoint String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
uri) (body -> Value
forall a. ToJSON a => a -> Value
toJSON body
body)
  Maybe res -> IO (Maybe res)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Response (Maybe res)
r Response (Maybe res)
-> Getting (Maybe res) (Response (Maybe res)) (Maybe res)
-> Maybe res
forall s a. s -> Getting a s a -> a
^. Getting (Maybe res) (Response (Maybe res)) (Maybe res)
forall body0 body1 (f :: * -> *).
Functor f =>
(body0 -> f body1) -> Response body0 -> f (Response body1)
responseBody)