{-# LANGUAGE DeriveDataTypeable, FlexibleContexts, OverloadedStrings #-}
module Facebook.Object.Order
    ( Order(..)
    , OrderId
    , OrderStatus(..)
    , OrderApplication(..)
    , getOrder
    ) where

import Control.Applicative
import Control.Monad (mzero)
import Control.Monad.Trans.Control (MonadBaseControl)
import Data.Text (Text)
import Data.Aeson ((.:), (.:?))
import Data.Typeable (Typeable)
import Data.Time.LocalTime (ZonedTime)

import qualified Control.Monad.Trans.Resource as R
import qualified Data.Aeson as A

import Facebook.Types
import Facebook.Monad
import Facebook.Graph

-- | 'Order' Id type.
type OrderId = Id

-- | A Facebook @Order@ oject.
data Order = Order {
    orderId             :: OrderId,
    orderFrom           :: UserId,
    orderTo             :: UserId,
    orderAmount         :: Integer,
    orderStatus         :: OrderStatus,
    orderApplication    :: OrderApplication,
    orderCountry        :: Text,
    orderRefundCode     :: Maybe Text,
    orderCreatedTime    :: ZonedTime,
    orderUpdatedTime    :: ZonedTime
} deriving (Show, Typeable)

-- | A Facebook 'Order' status type.
data OrderStatus =
    OrderPlaced
    | OrderSettled
    | OrderRefunded
    | OrderDisputed
    | OrderCancelled
    deriving (Show, Enum, Eq, Typeable)

-- | A trimmed down version of Facebook Application as it is used in 'Order'.
data OrderApplication = OrderApplication {
    appId   :: Text,
    appName :: Text
} deriving (Show, Typeable)

instance A.FromJSON OrderApplication where
    parseJSON (A.Object v)  =
        OrderApplication    <$> v .: "id"
                            <*> v .: "name"
    parseJSON _             = mzero

instance A.FromJSON Order where
    parseJSON (A.Object v) =
        Order   <$> v .: "id"
                <*> v .: "from"
                <*> v .: "to"
                <*> v .: "amount"
                <*> v .: "status"
                <*> v .: "application"
                <*> v .: "country"
                <*> v .:? "refund_reason_code"
                <*> v .: "created_time"
                <*> v .: "updated_time"
    parseJSON _ = mzero

instance A.FromJSON OrderStatus where
    parseJSON (A.String "placed")       = return OrderPlaced
    parseJSON (A.String "settled")      = return OrderSettled
    parseJSON (A.String "refunded")     = return OrderRefunded
    parseJSON (A.String "disputed")     = return OrderDisputed
    parseJSON (A.String "cancelled")    = return OrderCancelled
    parseJSON _                         = mzero

-- | Get an 'Order' using its 'OrderId'.  The user access token
-- is mandatory.
getOrder :: (R.MonadResource m, MonadBaseControl IO m) =>
           OrderId         -- ^ Order ID.
        -> UserAccessToken -- ^ User access token.
        -> FacebookT anyAuth m Order
getOrder id_ mtoken = getObject ("/" <> idCode id_) [] (Just mtoken)
