{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeApplications #-}

-- |
-- Module      : Network.Reddit.Message
-- Copyright   : (c) 2021 Rory Tyler Hayford
-- License     : BSD-3-Clause
-- Maintainer  : rory.hayford@protonmail.com
-- Stability   : experimental
-- Portability : GHC
--
-- Actions for messaging. These can be both comment replies as well as private
-- messages
--
module Network.Reddit.Message
    (  -- * Actions
      getInbox
    , getUnread
    , getSent
    , markRead
    , sendMessage
    , replyToMessage
    , reportMessage
      -- * Types
    , module M
    ) where

import           Data.Generics.Wrapped        ( wrappedTo )
import           Data.Text                    ( Text )

import           Lens.Micro

import           Network.Reddit.Internal
import           Network.Reddit.Types
import           Network.Reddit.Types.Item
import           Network.Reddit.Types.Message
import           Network.Reddit.Types.Message as M
                 ( Message(Message)
                 , MessageID
                 , MessageOpts(MessageOpts)
                 , NewMessage(NewMessage)
                 , PrivateMessageID(PrivateMessageID)
                 )
import           Network.Reddit.Utils

import           Web.FormUrlEncoded           ( ToForm(toForm) )
import           Web.HttpApiData              ( ToHttpApiData(toQueryParam) )

-- | Get the 'Message' inbox for the currently authenticated user
getInbox :: MonadReddit m
         => Paginator MessageID Message
         -> m (Listing MessageID Message)
getInbox :: Paginator MessageID Message -> m (Listing MessageID Message)
getInbox = Text
-> Paginator MessageID Message -> m (Listing MessageID Message)
forall (m :: * -> *).
MonadReddit m =>
Text
-> Paginator MessageID Message -> m (Listing MessageID Message)
msgs Text
"inbox"

-- | Get the unread 'Message's of the currently authenticated user
getUnread :: MonadReddit m
          => Paginator MessageID Message
          -> m (Listing MessageID Message)
getUnread :: Paginator MessageID Message -> m (Listing MessageID Message)
getUnread = Text
-> Paginator MessageID Message -> m (Listing MessageID Message)
forall (m :: * -> *).
MonadReddit m =>
Text
-> Paginator MessageID Message -> m (Listing MessageID Message)
msgs Text
"unread"

-- | Get the 'Message's sent by the currently authenticated user
getSent :: MonadReddit m
        => Paginator MessageID Message
        -> m (Listing MessageID Message)
getSent :: Paginator MessageID Message -> m (Listing MessageID Message)
getSent = Text
-> Paginator MessageID Message -> m (Listing MessageID Message)
forall (m :: * -> *).
MonadReddit m =>
Text
-> Paginator MessageID Message -> m (Listing MessageID Message)
msgs Text
"sent"

-- | Mark a 'Message' as read
markRead :: MonadReddit m => MessageID -> m ()
markRead :: MessageID -> m ()
markRead MessageID
mid =
    APIAction () -> m ()
forall (m :: * -> *). MonadReddit m => APIAction () -> m ()
runAction_ APIAction Any
forall a. APIAction a
defaultAPIAction
               { $sel:pathSegments:APIAction :: [Text]
pathSegments = [ Text
"api", Text
"read_message" ]
               , $sel:method:APIAction :: Method
method       = Method
POST
               , $sel:requestData:APIAction :: WithData
requestData  = [(Text, Text)] -> WithData
mkTextFormData [ (Text
"id", MessageID -> Text
forall a. Thing a => a -> Text
fullname MessageID
mid) ]
               }

-- | Send a 'NewMessage'  to another user
sendMessage :: MonadReddit m => NewMessage -> m ()
sendMessage :: NewMessage -> m ()
sendMessage NewMessage
newMsg =
    APIAction () -> m ()
forall (m :: * -> *). MonadReddit m => APIAction () -> m ()
runAction_ APIAction Any
forall a. APIAction a
defaultAPIAction
               { $sel:pathSegments:APIAction :: [Text]
pathSegments = [ Text
"api", Text
"compose" ]
               , $sel:method:APIAction :: Method
method       = Method
POST
               , $sel:requestData:APIAction :: WithData
requestData  = Form -> WithData
WithForm (Form -> WithData) -> Form -> WithData
forall a b. (a -> b) -> a -> b
$ NewMessage -> Form
forall a. ToForm a => a -> Form
toForm NewMessage
newMsg
               }

-- | Reply to a 'Message', returning the newly created 'Message'
replyToMessage :: MonadReddit m => MessageID -> Body -> m Message
replyToMessage :: MessageID -> Text -> m Message
replyToMessage MessageID
mid Text
txt = APIAction PostedMessage -> m PostedMessage
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction @PostedMessage APIAction PostedMessage
forall a. APIAction a
r m PostedMessage -> (PostedMessage -> Message) -> m Message
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> PostedMessage -> Message
forall s t a b. Wrapped s t a b => s -> a
wrappedTo
  where
    r :: APIAction a
r = APIAction Any
forall a. APIAction a
defaultAPIAction
        { $sel:pathSegments:APIAction :: [Text]
pathSegments = [ Text
"api", Text
"comment" ]
        , $sel:method:APIAction :: Method
method       = Method
POST
        , $sel:requestData:APIAction :: WithData
requestData  = Form -> WithData
WithForm
              (Form -> WithData) -> Form -> WithData
forall a b. (a -> b) -> a -> b
$ [(Text, Text)] -> Form
forall a. ToForm a => a -> Form
toForm @[(Text, Text)]
                       [ (Text
"thing_id", MessageID -> Text
forall a. Thing a => a -> Text
fullname MessageID
mid)
                       , (Text
"text", Text
txt)
                       , (Text
"api_type", Text
"json")
                       ]
        }

msgs :: MonadReddit m
     => Text
     -> Paginator MessageID Message
     -> m (Listing MessageID Message)
msgs :: Text
-> Paginator MessageID Message -> m (Listing MessageID Message)
msgs Text
path Paginator MessageID Message
paginator = APIAction (Listing MessageID Message)
-> m (Listing MessageID Message)
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction APIAction Any
forall a. APIAction a
defaultAPIAction
                                { $sel:pathSegments:APIAction :: [Text]
pathSegments = [ Text
"message", Text
path ]
                                , $sel:requestData:APIAction :: WithData
requestData  = Paginator MessageID Message -> WithData
forall t a. (Thing t, Paginable a) => Paginator t a -> WithData
paginatorToFormData Paginator MessageID Message
paginator
                                }

-- | Report a message, bringing it to the attention of the Reddit admins
reportMessage :: MonadReddit m => Report -> MessageID -> m ()
reportMessage :: Report -> MessageID -> m ()
reportMessage Report
r MessageID
mid =
    APIAction () -> m ()
forall (m :: * -> *). MonadReddit m => APIAction () -> m ()
runAction_ APIAction Any
forall a. APIAction a
defaultAPIAction
               { $sel:pathSegments:APIAction :: [Text]
pathSegments = [ Text
"api", Text
"report" ]
               , $sel:method:APIAction :: Method
method       = Method
POST
               , $sel:requestData:APIAction :: WithData
requestData  = [(Text, Text)] -> WithData
mkTextFormData [ (Text
"id", MessageID -> Text
forall a. ToHttpApiData a => a -> Text
toQueryParam MessageID
mid)
                                               , (Text
"reason", Report -> Text
forall a. ToHttpApiData a => a -> Text
toQueryParam Report
r)
                                               ]
               }