-- |
-- Smith JSON representiation decoders.
--
{-# LANGUAGE OverloadedStrings #-}
module Smith.Client.Serial.Decode (
    userinfo
  , certificate
  , authorityPublicKeys
  , errored
  , forbidden
  , parse
  ) where

import           Data.Aeson (Value, (.:), (.:?))
import           Data.Aeson.Types (Parser)
import qualified Data.Aeson as Aeson
import qualified Data.Aeson.Types as Aeson
import           Data.Bifunctor (Bifunctor (..))
import qualified Data.ByteString.Lazy as Lazy
import           Data.Text (Text)
import qualified Data.Text as Text

import           Smith.Client.Data.CertificateAuthority
import           Smith.Client.Data.Certificate
import           Smith.Client.Data.User
import           Smith.Client.Error


userinfo :: Value -> Parser UserInfo
userinfo =
  Aeson.withObject "UserInfo" $ \o ->
    UserInfo
      <$> o .: "sub"

certificate :: Value -> Parser Certificate
certificate =
  Aeson.withObject "Certificate" $ \o ->
    Certificate
      <$> o .: "certificate"

authorityPublicKeys :: Value -> Parser [AuthorityPublicKey]
authorityPublicKeys =
  Aeson.withObject "AuthorityPublicKeys" $ \o -> do
    o .: "public-keys" >>= pure . fmap AuthorityPublicKey

errored :: Value -> Parser SmithError
errored =
  Aeson.withObject "SmithError" $ \o ->
    SmithApplicationError
      <$> (ErrorCode <$> o .: "error")
      <*> (fmap ErrorMessage <$> o .:? "message")

forbidden :: Value -> Parser SmithError
forbidden =
  Aeson.withObject "SmithError" $ \o ->
    SmithAuthorizationError
      <$> (ErrorCode <$> o .: "error")
      <*> (fmap ErrorMessage <$> o .:? "message")

parse :: (Value -> Parser a) -> Lazy.ByteString -> Either Text a
parse to t =
  first Text.pack (Aeson.eitherDecode t) >>= \v -> case Aeson.parse to v of
    Aeson.Success a ->
      pure a
    Aeson.Error msg ->
      Left . Text.pack $ msg