{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}

module Network.PinPon.AWS
  ( runSNS
  ) where

import Protolude hiding (catch)
import Control.Lens ((^.))
import Control.Monad.Catch (catch)
import Control.Monad.Reader (asks)
import Control.Monad.Trans.AWS (runAWST, send)
import qualified Data.ByteString.Lazy as BL (ByteString)
import Data.ByteString.Lens (packedChars)
import Network.AWS.Data.Text (ToText(..))
import Network.AWS.Types (AWSRequest, Error(..), Rs, serializeMessage, serviceMessage)
import Network.HTTP.Client (HttpException(..), HttpExceptionContent(..))
import Servant (ServantErr(..), err502, err504, throwError)

import Network.PinPon.Config (App(..), Config(..))

runSNS :: (AWSRequest a) => a -> App (Rs a)
runSNS req =
  do env <- asks _env
     catch (runAWST env $ send req) $ throwError . snsErrToServant

snsErrToServant :: Error -> ServantErr
snsErrToServant e = (errCode e) { errBody = mconcat ["Upstream AWS SNS error: ", errMsg e ] }

errCode :: Error -> ServantErr
errCode (TransportError (HttpExceptionRequest _ ResponseTimeout)) = err504
errCode (TransportError (HttpExceptionRequest _ ConnectionTimeout)) = err504
errCode _ = err502

errMsg :: Error -> BL.ByteString
errMsg (ServiceError e) = maybe "Unspecified error" (toSL . toText) $ e ^. serviceMessage
errMsg (SerializeError e) = e ^. serializeMessage ^. packedChars
errMsg (TransportError e) = show e ^. packedChars