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

module CoinbasePro.Authenticated.Transfer
    ( TransferType (..)
    , Transfer (..)
    , TransferDetails (..)
    , WithdrawalTransfer (..)
    , DepositTransfer (..)
    ) 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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show
    toQueryParam :: TransferType -> Text
toQueryParam = String -> Text
pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show


newtype UserNonce = UserNonce Int
  deriving (UserNonce -> UserNonce -> Bool
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
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
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
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 -> Maybe UTCTime
tCompletedAt :: Maybe 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
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 = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"transfer" forall a b. (a -> b) -> a -> b
$ \Object
o -> Text
-> Text
-> CreatedAt
-> Maybe UTCTime
-> Maybe UTCTime
-> Maybe UTCTime
-> AccountId
-> Text
-> Maybe UserNonce
-> Double
-> TransferDetails
TransferDetails
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"id")
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"type")
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"created_at")
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"completed_at")
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"canceled_at")
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"processed_at")
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"account_id")
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"user_id")
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"user_nonce")
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (forall a. Read a => String -> a
read forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"amount")


data WithdrawalTransfer = WithdrawalTransfer
    { WithdrawalTransfer -> TransferDetails
wTransfer :: TransferDetails
    , WithdrawalTransfer -> WithdrawalDetails
wDetails  :: WithdrawalDetails
    } deriving Int -> WithdrawalTransfer -> ShowS
[WithdrawalTransfer] -> ShowS
WithdrawalTransfer -> String
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 = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"withdrawal transfer" forall a b. (a -> b) -> a -> b
$ \Object
o -> TransferDetails -> WithdrawalDetails -> WithdrawalTransfer
WithdrawalTransfer
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. FromJSON a => Value -> Parser a
parseJSON (Object -> Value
Object Object
o)
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"details"


data DepositTransfer = DepositTransfer
    { DepositTransfer -> TransferDetails
dTransfer :: TransferDetails
    , DepositTransfer -> DepositDetails
dDetails  :: DepositDetails
    } deriving Int -> DepositTransfer -> ShowS
[DepositTransfer] -> ShowS
DepositTransfer -> String
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 = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"deposit transfer" forall a b. (a -> b) -> a -> b
$ \Object
o -> TransferDetails -> DepositDetails -> DepositTransfer
DepositTransfer
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. FromJSON a => Value -> Parser a
parseJSON (Object -> Value
Object Object
o)
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"details"


data Transfer = Withdrawal WithdrawalTransfer | Deposit DepositTransfer
  deriving Int -> Transfer -> ShowS
[Transfer] -> ShowS
Transfer -> String
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 = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"transfer" forall a b. (a -> b) -> a -> b
$ \Object
o -> do
    Value
t <- Text -> Value
String forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"type"
    case Value
t of
      Value
"withdraw" -> WithdrawalTransfer -> Transfer
Withdrawal forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. FromJSON a => Value -> Parser a
parseJSON (Object -> Value
Object Object
o)
      Value
"deposit"  -> DepositTransfer -> Transfer
Deposit forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. FromJSON a => Value -> Parser a
parseJSON (Object -> Value
Object Object
o)
      Value
_          -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Unable to parse transfer"