{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE CPP #-}

module Facebook.Object.Checkin
  ( Checkin(..)
  , CheckinFrom(..)
  , getCheckin
  , createCheckin
  ) where
#if __GLASGOW_HASKELL__ <= 784
import Control.Applicative
#endif
import Control.Monad (mzero)
import Data.Aeson ((.:), (.:?))
import Data.Text (Text)
import Data.Time (UTCTime)
import Data.Typeable (Typeable)

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

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

-- | A Facebook check-in (see
-- <https://developers.facebook.com/docs/reference/api/checkin/>).
--
-- /NOTE:/ We still don't support all fields supported by
-- Facebook. Please fill an issue if you need access to any other
-- fields.
data Checkin = Checkin
  { checkinId :: Id
  , checkinFrom :: Maybe CheckinFrom
  , checkinPlace :: Maybe Place
  , checkinCreatedTime :: Maybe UTCTime
  , checkinTags :: Maybe (Pager Tag)
  , checkinMessage :: Maybe Text
  } deriving (Eq, Ord, Show, Read, Typeable)

instance A.FromJSON Checkin where
  parseJSON (A.Object v) =
    Checkin <$> v .: "id" <*> v .:? "from" <*> v .:? "place" <*>
    ((unFbUTCTime <$>) <$> v .:? "created_time") <*>
    v .:? "tags" <*>
    v .:? "message"
  parseJSON _ = mzero

-- | Information about the user who made the check-in.
data CheckinFrom = CheckinFrom
  { checkinFromId :: UserId
  , checkinFromName :: Text
  } deriving (Eq, Ord, Show, Read, Typeable)

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

-- | Get a checkin from its ID.  The user access token is
-- optional, but when provided more information can be returned
-- back by Facebook.
getCheckin
  :: (R.MonadResource m, R.MonadUnliftIO m, R.MonadThrow m)
  => Id -- ^ Checkin ID.
  -> [Argument] -- ^ Arguments to be passed to Facebook.
  -> Maybe UserAccessToken -- ^ Optional user access token.
  -> FacebookT anyAuth m Checkin
getCheckin id_ query mtoken = getObject ("/" <> idCode id_) query mtoken

-- | Creates a 'check-in' and returns its ID. Place and
-- coordinates are both required by Facebook.
createCheckin
  :: (R.MonadResource m, R.MonadUnliftIO m, R.MonadThrow m)
  => Id -- ^ Place ID.
  -> GeoCoordinates -- ^ Coordinates.
  -> [Argument] -- ^ Other arguments of the action.
  -> UserAccessToken -- ^ Required user access token.
  -> FacebookT Auth m Id
createCheckin pid coords args usertoken = do
  let body = ("place" #= pid) : ("coordinates" #= coords) : args
  postObject "me/checkins" body usertoken
