{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell   #-}

module CoinbasePro.MarketData.Types
    ( Product (..)
    , CBTime (..)
    , AggregateBookLevel (..)
    , FullBookLevel (..)
    , Trade (..)
    ) where

import           Data.Aeson        (FromJSON (..), withObject, (.:))
import           Data.Aeson.Casing (snakeCase)
import           Data.Aeson.TH     (defaultOptions, deriveJSON,
                                    fieldLabelModifier)
import           Data.Text         (Text, pack)
import           Data.Time.Clock   (UTCTime)
import           Web.HttpApiData   (ToHttpApiData (..))

import           CoinbasePro.Types (Price, ProductId, Side, Size, TradeId)


data Product = Product
    { Product -> ProductId
productId      :: ProductId
    , Product -> Text
baseCurrency   :: Text
    , Product -> Text
quoteCurrency  :: Text
    , Product -> Double
baseMinSize    :: Double
    , Product -> Double
baseMaxSize    :: Double
    , Product -> Double
quoteIncrement :: Double
    , Product -> Double
minMarketFunds :: Double
    , Product -> Double
maxMarketFunds :: Double
    } deriving (Product -> Product -> Bool
(Product -> Product -> Bool)
-> (Product -> Product -> Bool) -> Eq Product
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Product -> Product -> Bool
$c/= :: Product -> Product -> Bool
== :: Product -> Product -> Bool
$c== :: Product -> Product -> Bool
Eq, Int -> Product -> ShowS
[Product] -> ShowS
Product -> String
(Int -> Product -> ShowS)
-> (Product -> String) -> ([Product] -> ShowS) -> Show Product
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Product] -> ShowS
$cshowList :: [Product] -> ShowS
show :: Product -> String
$cshow :: Product -> String
showsPrec :: Int -> Product -> ShowS
$cshowsPrec :: Int -> Product -> ShowS
Show)


instance FromJSON Product where
    parseJSON :: Value -> Parser Product
parseJSON = String -> (Object -> Parser Product) -> Value -> Parser Product
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"product" ((Object -> Parser Product) -> Value -> Parser Product)
-> (Object -> Parser Product) -> Value -> Parser Product
forall a b. (a -> b) -> a -> b
$ \Object
o -> ProductId
-> Text
-> Text
-> Double
-> Double
-> Double
-> Double
-> Double
-> Product
Product
        (ProductId
 -> Text
 -> Text
 -> Double
 -> Double
 -> Double
 -> Double
 -> Double
 -> Product)
-> Parser ProductId
-> Parser
     (Text
      -> Text
      -> Double
      -> Double
      -> Double
      -> Double
      -> Double
      -> Product)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Text -> Parser ProductId
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"id"
        Parser
  (Text
   -> Text
   -> Double
   -> Double
   -> Double
   -> Double
   -> Double
   -> Product)
-> Parser Text
-> Parser
     (Text -> Double -> Double -> Double -> Double -> Double -> Product)
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
"base_currency"
        Parser
  (Text -> Double -> Double -> Double -> Double -> Double -> Product)
-> Parser Text
-> Parser
     (Double -> Double -> Double -> Double -> Double -> Product)
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
"quote_currency"
        Parser (Double -> Double -> Double -> Double -> Double -> Product)
-> Parser Double
-> Parser (Double -> Double -> Double -> Double -> Product)
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
"base_min_size")
        Parser (Double -> Double -> Double -> Double -> Product)
-> Parser Double -> Parser (Double -> Double -> Double -> Product)
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
"base_max_size")
        Parser (Double -> Double -> Double -> Product)
-> Parser Double -> Parser (Double -> Double -> Product)
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
"quote_increment")
        Parser (Double -> Double -> Product)
-> Parser Double -> Parser (Double -> Product)
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
"min_market_funds")
        Parser (Double -> Product) -> Parser Double -> Parser Product
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
"max_market_funds")


instance ToHttpApiData Product where
    toUrlPiece :: Product -> Text
toUrlPiece   = ProductId -> Text
forall a. ToHttpApiData a => a -> Text
toUrlPiece (ProductId -> Text) -> (Product -> ProductId) -> Product -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Product -> ProductId
productId
    toQueryParam :: Product -> Text
toQueryParam = ProductId -> Text
forall a. ToHttpApiData a => a -> Text
toQueryParam (ProductId -> Text) -> (Product -> ProductId) -> Product -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Product -> ProductId
productId


newtype CBTime = CBTime { CBTime -> UTCTime
unCBTime :: UTCTime } deriving (CBTime -> CBTime -> Bool
(CBTime -> CBTime -> Bool)
-> (CBTime -> CBTime -> Bool) -> Eq CBTime
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CBTime -> CBTime -> Bool
$c/= :: CBTime -> CBTime -> Bool
== :: CBTime -> CBTime -> Bool
$c== :: CBTime -> CBTime -> Bool
Eq, Int -> CBTime -> ShowS
[CBTime] -> ShowS
CBTime -> String
(Int -> CBTime -> ShowS)
-> (CBTime -> String) -> ([CBTime] -> ShowS) -> Show CBTime
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CBTime] -> ShowS
$cshowList :: [CBTime] -> ShowS
show :: CBTime -> String
$cshow :: CBTime -> String
showsPrec :: Int -> CBTime -> ShowS
$cshowsPrec :: Int -> CBTime -> ShowS
Show)


instance FromJSON CBTime where
    parseJSON :: Value -> Parser CBTime
parseJSON = String -> (Object -> Parser CBTime) -> Value -> Parser CBTime
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"time" ((Object -> Parser CBTime) -> Value -> Parser CBTime)
-> (Object -> Parser CBTime) -> Value -> Parser CBTime
forall a b. (a -> b) -> a -> b
$ \Object
o ->
      UTCTime -> CBTime
CBTime (UTCTime -> CBTime) -> Parser UTCTime -> Parser CBTime
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Text -> Parser UTCTime
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"iso"


data AggregateBookLevel = Best | TopFifty
    deriving (AggregateBookLevel -> AggregateBookLevel -> Bool
(AggregateBookLevel -> AggregateBookLevel -> Bool)
-> (AggregateBookLevel -> AggregateBookLevel -> Bool)
-> Eq AggregateBookLevel
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AggregateBookLevel -> AggregateBookLevel -> Bool
$c/= :: AggregateBookLevel -> AggregateBookLevel -> Bool
== :: AggregateBookLevel -> AggregateBookLevel -> Bool
$c== :: AggregateBookLevel -> AggregateBookLevel -> Bool
Eq, Int -> AggregateBookLevel -> ShowS
[AggregateBookLevel] -> ShowS
AggregateBookLevel -> String
(Int -> AggregateBookLevel -> ShowS)
-> (AggregateBookLevel -> String)
-> ([AggregateBookLevel] -> ShowS)
-> Show AggregateBookLevel
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AggregateBookLevel] -> ShowS
$cshowList :: [AggregateBookLevel] -> ShowS
show :: AggregateBookLevel -> String
$cshow :: AggregateBookLevel -> String
showsPrec :: Int -> AggregateBookLevel -> ShowS
$cshowsPrec :: Int -> AggregateBookLevel -> ShowS
Show)


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


aggregateBookLevel :: AggregateBookLevel -> Int
aggregateBookLevel :: AggregateBookLevel -> Int
aggregateBookLevel AggregateBookLevel
Best     = Int
1
aggregateBookLevel AggregateBookLevel
TopFifty = Int
2


data FullBookLevel = FullBookLevel


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


fullBookLevel :: FullBookLevel -> Int
fullBookLevel :: FullBookLevel -> Int
fullBookLevel FullBookLevel
FullBookLevel = Int
3


data Trade = Trade
    { Trade -> UTCTime
time    :: UTCTime
    , Trade -> TradeId
tradeId :: TradeId
    , Trade -> Price
price   :: Price
    , Trade -> Size
size    :: Size
    , Trade -> Side
side    :: Side
    } deriving (Trade -> Trade -> Bool
(Trade -> Trade -> Bool) -> (Trade -> Trade -> Bool) -> Eq Trade
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Trade -> Trade -> Bool
$c/= :: Trade -> Trade -> Bool
== :: Trade -> Trade -> Bool
$c== :: Trade -> Trade -> Bool
Eq, Int -> Trade -> ShowS
[Trade] -> ShowS
Trade -> String
(Int -> Trade -> ShowS)
-> (Trade -> String) -> ([Trade] -> ShowS) -> Show Trade
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Trade] -> ShowS
$cshowList :: [Trade] -> ShowS
show :: Trade -> String
$cshow :: Trade -> String
showsPrec :: Int -> Trade -> ShowS
$cshowsPrec :: Int -> Trade -> ShowS
Show)


deriveJSON defaultOptions { fieldLabelModifier = snakeCase } ''Trade