{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings          #-}

module CoinbasePro.Authenticated.Transfer
    ( TransferType (..)
    , Transfer (..)
    ) where

import           Data.Aeson                           (FromJSON (..), ToJSON,
                                                       Value (..), parseJSON,
                                                       withObject, (.:), (.:?))
import           Data.Text                            (Text, pack)
import           Data.Time.Clock                      (UTCTime)
import           Servant.API

import           CoinbasePro.Authenticated.Accounts   (AccountId)
import           CoinbasePro.Authenticated.Deposit    (DepositDetails)
import           CoinbasePro.Authenticated.Withdrawal (WithdrawalDetails)
import           CoinbasePro.Types                    (CreatedAt, UserId)


data TransferType = WithdrawTransferType | DepositTransferType


instance Show TransferType where
  show :: TransferType -> String
show TransferType
WithdrawTransferType = String
"withdraw"
  show TransferType
DepositTransferType  = String
"deposit"


instance ToHttpApiData TransferType where
    toUrlPiece :: TransferType -> Text
toUrlPiece   = String -> Text
pack (String -> Text)
-> (TransferType -> String) -> TransferType -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TransferType -> String
forall a. Show a => a -> String
show
    toQueryParam :: TransferType -> Text
toQueryParam = String -> Text
pack (String -> Text)
-> (TransferType -> String) -> TransferType -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TransferType -> String
forall a. Show a => a -> String
show


newtype UserNonce = UserNonce Int
  deriving (UserNonce -> UserNonce -> Bool
(UserNonce -> UserNonce -> Bool)
-> (UserNonce -> UserNonce -> Bool) -> Eq UserNonce
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UserNonce -> UserNonce -> Bool
$c/= :: UserNonce -> UserNonce -> Bool
== :: UserNonce -> UserNonce -> Bool
$c== :: UserNonce -> UserNonce -> Bool
Eq, Int -> UserNonce -> ShowS
[UserNonce] -> ShowS
UserNonce -> String
(Int -> UserNonce -> ShowS)
-> (UserNonce -> String)
-> ([UserNonce] -> ShowS)
-> Show UserNonce
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [UserNonce] -> ShowS
$cshowList :: [UserNonce] -> ShowS
show :: UserNonce -> String
$cshow :: UserNonce -> String
showsPrec :: Int -> UserNonce -> ShowS
$cshowsPrec :: Int -> UserNonce -> ShowS
Show, [UserNonce] -> Encoding
[UserNonce] -> Value
UserNonce -> Encoding
UserNonce -> Value
(UserNonce -> Value)
-> (UserNonce -> Encoding)
-> ([UserNonce] -> Value)
-> ([UserNonce] -> Encoding)
-> ToJSON UserNonce
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [UserNonce] -> Encoding
$ctoEncodingList :: [UserNonce] -> Encoding
toJSONList :: [UserNonce] -> Value
$ctoJSONList :: [UserNonce] -> Value
toEncoding :: UserNonce -> Encoding
$ctoEncoding :: UserNonce -> Encoding
toJSON :: UserNonce -> Value
$ctoJSON :: UserNonce -> Value
ToJSON, Value -> Parser [UserNonce]
Value -> Parser UserNonce
(Value -> Parser UserNonce)
-> (Value -> Parser [UserNonce]) -> FromJSON UserNonce
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [UserNonce]
$cparseJSONList :: Value -> Parser [UserNonce]
parseJSON :: Value -> Parser UserNonce
$cparseJSON :: Value -> Parser UserNonce
FromJSON)


data TransferDetails = TransferDetails
    { TransferDetails -> Text
tId          :: Text
    , TransferDetails -> Text
tType        :: Text
    , TransferDetails -> CreatedAt
tCreatedAt   :: CreatedAt
    , TransferDetails -> UTCTime
tCompletedAt :: UTCTime
    , TransferDetails -> Maybe UTCTime
tCanceledAt  :: Maybe UTCTime
    , TransferDetails -> Maybe UTCTime
tProcessedAt :: Maybe UTCTime
    , TransferDetails -> AccountId
tAccountId   :: AccountId
    , TransferDetails -> Text
tUserId      :: UserId
    , TransferDetails -> Maybe UserNonce
tUserNonce   :: Maybe UserNonce
    , TransferDetails -> Double
tAmount      :: Double
    } deriving Int -> TransferDetails -> ShowS
[TransferDetails] -> ShowS
TransferDetails -> String
(Int -> TransferDetails -> ShowS)
-> (TransferDetails -> String)
-> ([TransferDetails] -> ShowS)
-> Show TransferDetails
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TransferDetails] -> ShowS
$cshowList :: [TransferDetails] -> ShowS
show :: TransferDetails -> String
$cshow :: TransferDetails -> String
showsPrec :: Int -> TransferDetails -> ShowS
$cshowsPrec :: Int -> TransferDetails -> ShowS
Show


instance FromJSON TransferDetails where
  parseJSON :: Value -> Parser TransferDetails
parseJSON = String
-> (Object -> Parser TransferDetails)
-> Value
-> Parser TransferDetails
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"transfer" ((Object -> Parser TransferDetails)
 -> Value -> Parser TransferDetails)
-> (Object -> Parser TransferDetails)
-> Value
-> Parser TransferDetails
forall a b. (a -> b) -> a -> b
$ \Object
o -> Text
-> Text
-> CreatedAt
-> UTCTime
-> Maybe UTCTime
-> Maybe UTCTime
-> AccountId
-> Text
-> Maybe UserNonce
-> Double
-> TransferDetails
TransferDetails
    (Text
 -> Text
 -> CreatedAt
 -> UTCTime
 -> Maybe UTCTime
 -> Maybe UTCTime
 -> AccountId
 -> Text
 -> Maybe UserNonce
 -> Double
 -> TransferDetails)
-> Parser Text
-> Parser
     (Text
      -> CreatedAt
      -> UTCTime
      -> Maybe UTCTime
      -> Maybe UTCTime
      -> AccountId
      -> Text
      -> Maybe UserNonce
      -> Double
      -> TransferDetails)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Object
o Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"id")
    Parser
  (Text
   -> CreatedAt
   -> UTCTime
   -> Maybe UTCTime
   -> Maybe UTCTime
   -> AccountId
   -> Text
   -> Maybe UserNonce
   -> Double
   -> TransferDetails)
-> Parser Text
-> Parser
     (CreatedAt
      -> UTCTime
      -> Maybe UTCTime
      -> Maybe UTCTime
      -> AccountId
      -> Text
      -> Maybe UserNonce
      -> Double
      -> TransferDetails)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"type")
    Parser
  (CreatedAt
   -> UTCTime
   -> Maybe UTCTime
   -> Maybe UTCTime
   -> AccountId
   -> Text
   -> Maybe UserNonce
   -> Double
   -> TransferDetails)
-> Parser CreatedAt
-> Parser
     (UTCTime
      -> Maybe UTCTime
      -> Maybe UTCTime
      -> AccountId
      -> Text
      -> Maybe UserNonce
      -> Double
      -> TransferDetails)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o Object -> Text -> Parser CreatedAt
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"created_at")
    Parser
  (UTCTime
   -> Maybe UTCTime
   -> Maybe UTCTime
   -> AccountId
   -> Text
   -> Maybe UserNonce
   -> Double
   -> TransferDetails)
-> Parser UTCTime
-> Parser
     (Maybe UTCTime
      -> Maybe UTCTime
      -> AccountId
      -> Text
      -> Maybe UserNonce
      -> Double
      -> TransferDetails)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o Object -> Text -> Parser UTCTime
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"completed_at")
    Parser
  (Maybe UTCTime
   -> Maybe UTCTime
   -> AccountId
   -> Text
   -> Maybe UserNonce
   -> Double
   -> TransferDetails)
-> Parser (Maybe UTCTime)
-> Parser
     (Maybe UTCTime
      -> AccountId
      -> Text
      -> Maybe UserNonce
      -> Double
      -> TransferDetails)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o Object -> Text -> Parser (Maybe UTCTime)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"canceled_at")
    Parser
  (Maybe UTCTime
   -> AccountId
   -> Text
   -> Maybe UserNonce
   -> Double
   -> TransferDetails)
-> Parser (Maybe UTCTime)
-> Parser
     (AccountId -> Text -> Maybe UserNonce -> Double -> TransferDetails)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o Object -> Text -> Parser (Maybe UTCTime)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"processed_at")
    Parser
  (AccountId -> Text -> Maybe UserNonce -> Double -> TransferDetails)
-> Parser AccountId
-> Parser (Text -> Maybe UserNonce -> Double -> TransferDetails)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o Object -> Text -> Parser AccountId
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"account_id")
    Parser (Text -> Maybe UserNonce -> Double -> TransferDetails)
-> Parser Text
-> Parser (Maybe UserNonce -> Double -> TransferDetails)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"user_id")
    Parser (Maybe UserNonce -> Double -> TransferDetails)
-> Parser (Maybe UserNonce) -> Parser (Double -> TransferDetails)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o Object -> Text -> Parser (Maybe UserNonce)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"user_nonce")
    Parser (Double -> TransferDetails)
-> Parser Double -> Parser TransferDetails
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (String -> Double
forall a. Read a => String -> a
read (String -> Double) -> Parser String -> Parser Double
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Text -> Parser String
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"amount")


data WithdrawalTransfer = WithdrawalTransfer
    { WithdrawalTransfer -> TransferDetails
wTransfer :: TransferDetails
    , WithdrawalTransfer -> WithdrawalDetails
wDetails  :: WithdrawalDetails
    } deriving Int -> WithdrawalTransfer -> ShowS
[WithdrawalTransfer] -> ShowS
WithdrawalTransfer -> String
(Int -> WithdrawalTransfer -> ShowS)
-> (WithdrawalTransfer -> String)
-> ([WithdrawalTransfer] -> ShowS)
-> Show WithdrawalTransfer
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [WithdrawalTransfer] -> ShowS
$cshowList :: [WithdrawalTransfer] -> ShowS
show :: WithdrawalTransfer -> String
$cshow :: WithdrawalTransfer -> String
showsPrec :: Int -> WithdrawalTransfer -> ShowS
$cshowsPrec :: Int -> WithdrawalTransfer -> ShowS
Show


instance FromJSON WithdrawalTransfer where
  parseJSON :: Value -> Parser WithdrawalTransfer
parseJSON = String
-> (Object -> Parser WithdrawalTransfer)
-> Value
-> Parser WithdrawalTransfer
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"withdrawal transfer" ((Object -> Parser WithdrawalTransfer)
 -> Value -> Parser WithdrawalTransfer)
-> (Object -> Parser WithdrawalTransfer)
-> Value
-> Parser WithdrawalTransfer
forall a b. (a -> b) -> a -> b
$ \Object
o -> TransferDetails -> WithdrawalDetails -> WithdrawalTransfer
WithdrawalTransfer
    (TransferDetails -> WithdrawalDetails -> WithdrawalTransfer)
-> Parser TransferDetails
-> Parser (WithdrawalDetails -> WithdrawalTransfer)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser TransferDetails
forall a. FromJSON a => Value -> Parser a
parseJSON (Object -> Value
Object Object
o)
    Parser (WithdrawalDetails -> WithdrawalTransfer)
-> Parser WithdrawalDetails -> Parser WithdrawalTransfer
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o Object -> Text -> Parser WithdrawalDetails
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"details"


data DepositTransfer = DepositTransfer
    { DepositTransfer -> TransferDetails
dTransfer :: TransferDetails
    , DepositTransfer -> DepositDetails
dDetails  :: DepositDetails
    } deriving Int -> DepositTransfer -> ShowS
[DepositTransfer] -> ShowS
DepositTransfer -> String
(Int -> DepositTransfer -> ShowS)
-> (DepositTransfer -> String)
-> ([DepositTransfer] -> ShowS)
-> Show DepositTransfer
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DepositTransfer] -> ShowS
$cshowList :: [DepositTransfer] -> ShowS
show :: DepositTransfer -> String
$cshow :: DepositTransfer -> String
showsPrec :: Int -> DepositTransfer -> ShowS
$cshowsPrec :: Int -> DepositTransfer -> ShowS
Show


instance FromJSON DepositTransfer where
  parseJSON :: Value -> Parser DepositTransfer
parseJSON = String
-> (Object -> Parser DepositTransfer)
-> Value
-> Parser DepositTransfer
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"deposit transfer" ((Object -> Parser DepositTransfer)
 -> Value -> Parser DepositTransfer)
-> (Object -> Parser DepositTransfer)
-> Value
-> Parser DepositTransfer
forall a b. (a -> b) -> a -> b
$ \Object
o -> TransferDetails -> DepositDetails -> DepositTransfer
DepositTransfer
    (TransferDetails -> DepositDetails -> DepositTransfer)
-> Parser TransferDetails
-> Parser (DepositDetails -> DepositTransfer)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser TransferDetails
forall a. FromJSON a => Value -> Parser a
parseJSON (Object -> Value
Object Object
o)
    Parser (DepositDetails -> DepositTransfer)
-> Parser DepositDetails -> Parser DepositTransfer
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o Object -> Text -> Parser DepositDetails
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"details"


data Transfer = Withdrawal WithdrawalTransfer | Deposit DepositTransfer
  deriving Int -> Transfer -> ShowS
[Transfer] -> ShowS
Transfer -> String
(Int -> Transfer -> ShowS)
-> (Transfer -> String) -> ([Transfer] -> ShowS) -> Show Transfer
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Transfer] -> ShowS
$cshowList :: [Transfer] -> ShowS
show :: Transfer -> String
$cshow :: Transfer -> String
showsPrec :: Int -> Transfer -> ShowS
$cshowsPrec :: Int -> Transfer -> ShowS
Show


instance FromJSON Transfer where
  parseJSON :: Value -> Parser Transfer
parseJSON = String -> (Object -> Parser Transfer) -> Value -> Parser Transfer
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"transfer" ((Object -> Parser Transfer) -> Value -> Parser Transfer)
-> (Object -> Parser Transfer) -> Value -> Parser Transfer
forall a b. (a -> b) -> a -> b
$ \Object
o -> do
    Value
t <- Text -> Value
String (Text -> Value) -> Parser Text -> Parser Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"type"
    case Value
t of
      Value
"withdraw" -> WithdrawalTransfer -> Transfer
Withdrawal (WithdrawalTransfer -> Transfer)
-> Parser WithdrawalTransfer -> Parser Transfer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser WithdrawalTransfer
forall a. FromJSON a => Value -> Parser a
parseJSON (Object -> Value
Object Object
o)
      Value
"deposit"  -> DepositTransfer -> Transfer
Deposit (DepositTransfer -> Transfer)
-> Parser DepositTransfer -> Parser Transfer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser DepositTransfer
forall a. FromJSON a => Value -> Parser a
parseJSON (Object -> Value
Object Object
o)
      Value
_          -> String -> Parser Transfer
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Unable to parse transfer"