{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase                 #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE TemplateHaskell            #-}

module CoinbasePro.Authenticated.Report
  ( ReportId (..)
  , ReportRequest (..)
  , ReportResponse (..)

  , FillsReportRequest
  , AccountsReportRequest

  , accountsReportRequest
  , fillsReportRequest
  ) where

import           Data.Aeson                         (ToJSON (..), object, (.=))
import           Data.Aeson.Casing                  (snakeCase)
import           Data.Aeson.TH                      (constructorTagModifier,
                                                     defaultOptions, deriveJSON,
                                                     fieldLabelModifier,
                                                     unwrapUnaryRecords)
import qualified Data.Char                          as Char
import           Data.Text                          (Text)
import           Data.Time.Clock                    (UTCTime)
import           Data.UUID                          (UUID)
import           Servant.API                        (ToHttpApiData)

import           CoinbasePro.Authenticated.Accounts (AccountId)
import           CoinbasePro.Types                  (CreatedAt, ProductId)


newtype ReportId = ReportId { ReportId -> UUID
unReportId:: UUID }
  deriving (ReportId -> ReportId -> Bool
(ReportId -> ReportId -> Bool)
-> (ReportId -> ReportId -> Bool) -> Eq ReportId
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ReportId -> ReportId -> Bool
$c/= :: ReportId -> ReportId -> Bool
== :: ReportId -> ReportId -> Bool
$c== :: ReportId -> ReportId -> Bool
Eq, Int -> ReportId -> ShowS
[ReportId] -> ShowS
ReportId -> String
(Int -> ReportId -> ShowS)
-> (ReportId -> String) -> ([ReportId] -> ShowS) -> Show ReportId
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ReportId] -> ShowS
$cshowList :: [ReportId] -> ShowS
show :: ReportId -> String
$cshow :: ReportId -> String
showsPrec :: Int -> ReportId -> ShowS
$cshowsPrec :: Int -> ReportId -> ShowS
Show, ReportId -> ByteString
ReportId -> Builder
ReportId -> Text
(ReportId -> Text)
-> (ReportId -> Builder)
-> (ReportId -> ByteString)
-> (ReportId -> Text)
-> ToHttpApiData ReportId
forall a.
(a -> Text)
-> (a -> Builder)
-> (a -> ByteString)
-> (a -> Text)
-> ToHttpApiData a
toQueryParam :: ReportId -> Text
$ctoQueryParam :: ReportId -> Text
toHeader :: ReportId -> ByteString
$ctoHeader :: ReportId -> ByteString
toEncodedUrlPiece :: ReportId -> Builder
$ctoEncodedUrlPiece :: ReportId -> Builder
toUrlPiece :: ReportId -> Text
$ctoUrlPiece :: ReportId -> Text
ToHttpApiData)


deriveJSON defaultOptions
    { fieldLabelModifier = snakeCase
    , unwrapUnaryRecords = True
    } ''ReportId


data ReportFormat = PDF | CSV
    deriving Int -> ReportFormat -> ShowS
[ReportFormat] -> ShowS
ReportFormat -> String
(Int -> ReportFormat -> ShowS)
-> (ReportFormat -> String)
-> ([ReportFormat] -> ShowS)
-> Show ReportFormat
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ReportFormat] -> ShowS
$cshowList :: [ReportFormat] -> ShowS
show :: ReportFormat -> String
$cshow :: ReportFormat -> String
showsPrec :: Int -> ReportFormat -> ShowS
$cshowsPrec :: Int -> ReportFormat -> ShowS
Show


deriveJSON defaultOptions { constructorTagModifier = fmap Char.toLower } ''ReportFormat


newtype Email = Email Text
    deriving Int -> Email -> ShowS
[Email] -> ShowS
Email -> String
(Int -> Email -> ShowS)
-> (Email -> String) -> ([Email] -> ShowS) -> Show Email
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Email] -> ShowS
$cshowList :: [Email] -> ShowS
show :: Email -> String
$cshow :: Email -> String
showsPrec :: Int -> Email -> ShowS
$cshowsPrec :: Int -> Email -> ShowS
Show


deriveJSON defaultOptions { fieldLabelModifier = snakeCase } ''Email


data Request = Request
    { Request -> UTCTime
rStartDate :: UTCTime
    , Request -> UTCTime
rEndDate   :: UTCTime
    , Request -> Maybe ReportFormat
rFormat    :: Maybe ReportFormat
    , Request -> Maybe Email
rEmail     :: Maybe Email
    } deriving Int -> Request -> ShowS
[Request] -> ShowS
Request -> String
(Int -> Request -> ShowS)
-> (Request -> String) -> ([Request] -> ShowS) -> Show Request
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Request] -> ShowS
$cshowList :: [Request] -> ShowS
show :: Request -> String
$cshow :: Request -> String
showsPrec :: Int -> Request -> ShowS
$cshowsPrec :: Int -> Request -> ShowS
Show


data FillsReportRequest = FillsReportRequest
    { FillsReportRequest -> ProductId
frProductId :: ProductId
    , FillsReportRequest -> Maybe AccountId
frAccountId :: Maybe AccountId
    , FillsReportRequest -> Request
frRequest   :: Request
    } deriving Int -> FillsReportRequest -> ShowS
[FillsReportRequest] -> ShowS
FillsReportRequest -> String
(Int -> FillsReportRequest -> ShowS)
-> (FillsReportRequest -> String)
-> ([FillsReportRequest] -> ShowS)
-> Show FillsReportRequest
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FillsReportRequest] -> ShowS
$cshowList :: [FillsReportRequest] -> ShowS
show :: FillsReportRequest -> String
$cshow :: FillsReportRequest -> String
showsPrec :: Int -> FillsReportRequest -> ShowS
$cshowsPrec :: Int -> FillsReportRequest -> ShowS
Show


data AccountsReportRequest = AccountsReportRequest
    { AccountsReportRequest -> AccountId
arAccountId :: AccountId
    , AccountsReportRequest -> Maybe ProductId
arProductId :: Maybe ProductId
    , AccountsReportRequest -> Request
arRequest   :: Request
    } deriving Int -> AccountsReportRequest -> ShowS
[AccountsReportRequest] -> ShowS
AccountsReportRequest -> String
(Int -> AccountsReportRequest -> ShowS)
-> (AccountsReportRequest -> String)
-> ([AccountsReportRequest] -> ShowS)
-> Show AccountsReportRequest
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AccountsReportRequest] -> ShowS
$cshowList :: [AccountsReportRequest] -> ShowS
show :: AccountsReportRequest -> String
$cshow :: AccountsReportRequest -> String
showsPrec :: Int -> AccountsReportRequest -> ShowS
$cshowsPrec :: Int -> AccountsReportRequest -> ShowS
Show


data ReportRequest = Fills FillsReportRequest | Accounts AccountsReportRequest
    deriving Int -> ReportRequest -> ShowS
[ReportRequest] -> ShowS
ReportRequest -> String
(Int -> ReportRequest -> ShowS)
-> (ReportRequest -> String)
-> ([ReportRequest] -> ShowS)
-> Show ReportRequest
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ReportRequest] -> ShowS
$cshowList :: [ReportRequest] -> ShowS
show :: ReportRequest -> String
$cshow :: ReportRequest -> String
showsPrec :: Int -> ReportRequest -> ShowS
$cshowsPrec :: Int -> ReportRequest -> ShowS
Show


accountsReportRequest :: AccountId
                      -> Maybe ProductId
                      -- ^ start date
                      -> UTCTime
                      -- ^ end date
                      -> UTCTime
                      -- ^ pdf or csv
                      -> Maybe ReportFormat
                      -> Maybe Email
                      -> ReportRequest
accountsReportRequest :: AccountId
-> Maybe ProductId
-> UTCTime
-> UTCTime
-> Maybe ReportFormat
-> Maybe Email
-> ReportRequest
accountsReportRequest AccountId
aid Maybe ProductId
prid UTCTime
start UTCTime
end Maybe ReportFormat
format =
  AccountsReportRequest -> ReportRequest
Accounts (AccountsReportRequest -> ReportRequest)
-> (Maybe Email -> AccountsReportRequest)
-> Maybe Email
-> ReportRequest
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AccountId -> Maybe ProductId -> Request -> AccountsReportRequest
AccountsReportRequest AccountId
aid Maybe ProductId
prid (Request -> AccountsReportRequest)
-> (Maybe Email -> Request) -> Maybe Email -> AccountsReportRequest
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UTCTime -> UTCTime -> Maybe ReportFormat -> Maybe Email -> Request
Request UTCTime
start UTCTime
end Maybe ReportFormat
format


fillsReportRequest :: ProductId
                   -> Maybe AccountId
                   -- ^ start date
                   -> UTCTime
                   -- ^ end date
                   -> UTCTime
                   -- ^ pdf or csv
                   -> Maybe ReportFormat
                   -> Maybe Email
                   -> ReportRequest
fillsReportRequest :: ProductId
-> Maybe AccountId
-> UTCTime
-> UTCTime
-> Maybe ReportFormat
-> Maybe Email
-> ReportRequest
fillsReportRequest ProductId
prid Maybe AccountId
aid UTCTime
start UTCTime
end Maybe ReportFormat
format =
  FillsReportRequest -> ReportRequest
Fills (FillsReportRequest -> ReportRequest)
-> (Maybe Email -> FillsReportRequest)
-> Maybe Email
-> ReportRequest
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProductId -> Maybe AccountId -> Request -> FillsReportRequest
FillsReportRequest ProductId
prid Maybe AccountId
aid (Request -> FillsReportRequest)
-> (Maybe Email -> Request) -> Maybe Email -> FillsReportRequest
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UTCTime -> UTCTime -> Maybe ReportFormat -> Maybe Email -> Request
Request UTCTime
start UTCTime
end Maybe ReportFormat
format


instance ToJSON ReportRequest where
    toJSON :: ReportRequest -> Value
toJSON (Fills FillsReportRequest
frr) =
      [Pair] -> Value
object ([ Text
"type"       Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= (Text
"fills" :: Text)
              , Text
"start_date" Text -> UTCTime -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Request -> UTCTime
rStartDate (FillsReportRequest -> Request
frRequest FillsReportRequest
frr)
              , Text
"end_date"   Text -> UTCTime -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Request -> UTCTime
rEndDate (FillsReportRequest -> Request
frRequest FillsReportRequest
frr)
              , Text
"product_id" Text -> ProductId -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= FillsReportRequest -> ProductId
frProductId FillsReportRequest
frr
              ] [Pair] -> [Pair] -> [Pair]
forall a. Semigroup a => a -> a -> a
<> [Pair] -> (AccountId -> [Pair]) -> Maybe AccountId -> [Pair]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Pair]
forall a. Monoid a => a
mempty (\AccountId
aid -> [Text
"account_id" Text -> AccountId -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= AccountId
aid]) (FillsReportRequest -> Maybe AccountId
frAccountId FillsReportRequest
frr)
                [Pair] -> [Pair] -> [Pair]
forall a. Semigroup a => a -> a -> a
<> [Pair] -> (Email -> [Pair]) -> Maybe Email -> [Pair]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Pair]
forall a. Monoid a => a
mempty (\Email
em  -> [Text
"email" Text -> Email -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Email
em]) (Request -> Maybe Email
rEmail (FillsReportRequest -> Request
frRequest FillsReportRequest
frr))
                [Pair] -> [Pair] -> [Pair]
forall a. Semigroup a => a -> a -> a
<> [Pair] -> (ReportFormat -> [Pair]) -> Maybe ReportFormat -> [Pair]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Pair]
forall a. Monoid a => a
mempty (\ReportFormat
fmt -> [Text
"format" Text -> ReportFormat -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= ReportFormat
fmt]) (Request -> Maybe ReportFormat
rFormat (FillsReportRequest -> Request
frRequest FillsReportRequest
frr))
             )
    toJSON (Accounts AccountsReportRequest
arr) =
      [Pair] -> Value
object ([ Text
"type"       Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= (Text
"account" :: Text)
              , Text
"start_date" Text -> UTCTime -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Request -> UTCTime
rStartDate (AccountsReportRequest -> Request
arRequest AccountsReportRequest
arr)
              , Text
"end_date"   Text -> UTCTime -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Request -> UTCTime
rEndDate (AccountsReportRequest -> Request
arRequest AccountsReportRequest
arr)
              , Text
"account_id" Text -> AccountId -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= AccountsReportRequest -> AccountId
arAccountId AccountsReportRequest
arr
              ] [Pair] -> [Pair] -> [Pair]
forall a. Semigroup a => a -> a -> a
<> [Pair] -> (ProductId -> [Pair]) -> Maybe ProductId -> [Pair]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Pair]
forall a. Monoid a => a
mempty (\ProductId
prid -> [Text
"product_id" Text -> ProductId -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= ProductId
prid]) (AccountsReportRequest -> Maybe ProductId
arProductId AccountsReportRequest
arr)
                [Pair] -> [Pair] -> [Pair]
forall a. Semigroup a => a -> a -> a
<> [Pair] -> (Email -> [Pair]) -> Maybe Email -> [Pair]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Pair]
forall a. Monoid a => a
mempty (\Email
em   -> [Text
"email" Text -> Email -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Email
em]) (Request -> Maybe Email
rEmail (AccountsReportRequest -> Request
arRequest AccountsReportRequest
arr))
                [Pair] -> [Pair] -> [Pair]
forall a. Semigroup a => a -> a -> a
<> [Pair] -> (ReportFormat -> [Pair]) -> Maybe ReportFormat -> [Pair]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Pair]
forall a. Monoid a => a
mempty (\ReportFormat
fmt  -> [Text
"format" Text -> ReportFormat -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= ReportFormat
fmt]) (Request -> Maybe ReportFormat
rFormat (AccountsReportRequest -> Request
arRequest AccountsReportRequest
arr))
             )


data ReportRequestType = FillsType | AccountType


instance Show ReportRequestType where
    show :: ReportRequestType -> String
show ReportRequestType
FillsType   = String
"fills"
    show ReportRequestType
AccountType = String
"account"


deriveJSON defaultOptions { constructorTagModifier = snakeCase . init . init . init . init } ''ReportRequestType


data ReportStatus = Pending | Creating | Ready


instance Show ReportStatus where
    show :: ReportStatus -> String
show ReportStatus
Pending  = String
"pending"
    show ReportStatus
Creating = String
"creating"
    show ReportStatus
Ready    = String
"ready"


deriveJSON defaultOptions { constructorTagModifier = fmap Char.toLower
                          , fieldLabelModifier = snakeCase
                          } ''ReportStatus


data ReportParams = ReportParams
    { ReportParams -> UTCTime
startDate :: UTCTime
    , ReportParams -> UTCTime
endDate   :: UTCTime
    } deriving Int -> ReportParams -> ShowS
[ReportParams] -> ShowS
ReportParams -> String
(Int -> ReportParams -> ShowS)
-> (ReportParams -> String)
-> ([ReportParams] -> ShowS)
-> Show ReportParams
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ReportParams] -> ShowS
$cshowList :: [ReportParams] -> ShowS
show :: ReportParams -> String
$cshow :: ReportParams -> String
showsPrec :: Int -> ReportParams -> ShowS
$cshowsPrec :: Int -> ReportParams -> ShowS
Show


deriveJSON defaultOptions { fieldLabelModifier = snakeCase } ''ReportParams


{-|
  Example JSON Response:
  {
    "id": "0428b97b-bec1-429e-a94c-59232926778d",
    "type": "fills",
    "status": "pending",
    "created_at": "2015-01-06T10:34:47.000Z",
    "completed_at": undefined,
    "expires_at": "2015-01-13T10:35:47.000Z",
    "file_url": undefined,
    "params": {
        "start_date": "2014-11-01T00:00:00.000Z",
        "end_date": "2014-11-30T23:59:59.000Z"
    }
  }
-}
data ReportResponse = ReportResponse
    { ReportResponse -> ReportId
rrId          :: ReportId
    , ReportResponse -> ReportRequestType
rrType        :: ReportRequestType
    , ReportResponse -> ReportStatus
rrStatus      :: ReportStatus
    , ReportResponse -> Maybe CreatedAt
rrCreatedAt   :: Maybe CreatedAt
    , ReportResponse -> Maybe UTCTime
rrCompletedAt :: Maybe UTCTime
    , ReportResponse -> Maybe UTCTime
rrExpiresAt   :: Maybe UTCTime
    , ReportResponse -> Maybe Text
rrFileUrl     :: Maybe Text
    , ReportResponse -> Maybe ReportParams
rrParams      :: Maybe ReportParams
    } deriving Int -> ReportResponse -> ShowS
[ReportResponse] -> ShowS
ReportResponse -> String
(Int -> ReportResponse -> ShowS)
-> (ReportResponse -> String)
-> ([ReportResponse] -> ShowS)
-> Show ReportResponse
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ReportResponse] -> ShowS
$cshowList :: [ReportResponse] -> ShowS
show :: ReportResponse -> String
$cshow :: ReportResponse -> String
showsPrec :: Int -> ReportResponse -> ShowS
$cshowsPrec :: Int -> ReportResponse -> ShowS
Show


deriveJSON defaultOptions { fieldLabelModifier = snakeCase . drop 2 } ''ReportResponse