content: -- | Contains comment-related actions, like editing comments
  --   and performing moderator actions on posts.
  module Reddit.Actions.Comment
    ( getNewComments
    , getNewComments'
    , getMoreChildren
    , getCommentInfo
    , getCommentsInfo
    , editComment
    , deleteComment
    , removeComment ) where
  
  import Reddit.Types.Comment
  import Reddit.Types.Empty
  import Reddit.Types.Error
  import Reddit.Types.Listing
  import Reddit.Types.Options
  import Reddit.Types.Post
  import Reddit.Types.Reddit
  import Reddit.Types.Subreddit
  import qualified Reddit.Routes as Route
  
  import Data.Default.Class
  import Data.Text (Text)
  import Network.API.Builder (APIError(..))
  
  -- | Get a 'CommentListing' for the most recent comments on the site overall.
  --   This maps to <http://reddit.com/r/$SUBREDDIT/comments>, or <http://reddit.com/comments>
  --   if the subreddit is not specified.
  --   Note that none of the comments returned will have any child comments.
  getNewComments :: Monad m => Maybe SubredditName -> RedditT m CommentListing
  getNewComments = getNewComments' def
  
  -- | Get a 'CommentListing' for the most recent comments with the specified 'Options' and
  --   'SubredditName'. Note that none of the comments returned will have any child comments.
  --   If the 'Options' is 'def', then this function is identical to 'getNewComments'.
  getNewComments' :: Monad m => Options CommentID -> Maybe SubredditName -> RedditT m CommentListing
  getNewComments' opts r = runRoute $ Route.newComments opts r
  
  -- | Expand children comments that weren't fetched on initial load.
  --   Equivalent to the web UI's "load more comments" button.
  getMoreChildren :: Monad m
                  => PostID -- ^ @PostID@ for the top-level
                  -> [CommentID] -- ^ List of @CommentID@s to expand
                  -> RedditT m [CommentReference]
  getMoreChildren _ [] = return []
  getMoreChildren p cs = do
    let (now, next) = splitAt 20 cs
    POSTWrapped rs <- runRoute $ Route.moreChildren p now
    more <- getMoreChildren p next
    return $ rs ++ more
  
  -- | Given a 'CommentID', 'getCommentInfo' will return the full details for that comment.
  getCommentInfo :: Monad m => CommentID -> RedditT m Comment
  getCommentInfo c = do
    res <- getCommentsInfo [c]
    case res of
      Listing _ _ [comment] -> return comment
      _ -> failWith $ APIError InvalidResponseError
  
  -- | Given a list of 'CommentID's, 'getCommentsInfo' will return another list containing
  --   the full details for all the comments. Note that Reddit's
  --   API imposes a limitation of 100 comments per request, so this function will fail immediately if given a list of more than 100 IDs.
  getCommentsInfo :: Monad m => [CommentID] -> RedditT m CommentListing
  getCommentsInfo cs =
    if null $ drop 100 cs
      then do
        res <- runRoute $ Route.commentsInfo cs
        case res of
          Listing _ _ comments | sameLength comments cs ->
            return res
          _ -> failWith $ APIError InvalidResponseError
      else failWith $ APIError TooManyRequests
    where
      sameLength (_:xs) (_:ys) = sameLength xs ys
      sameLength [] [] = True
      sameLength _ _ = False
  
  -- | Edit a comment.
  editComment :: Monad m
              => CommentID -- ^ Comment to edit
              -> Text -- ^ New comment text
              -> RedditT m Comment
  editComment thing text = do
    POSTWrapped res <- runRoute $ Route.edit thing text
    return res
  
  -- | Deletes one of your own comments. Note that this is different from
  --   removing a comment as a moderator action.
  deleteComment :: Monad m => CommentID -> RedditT m ()
  deleteComment = nothing . runRoute . Route.delete
  
  -- | Removes a comment (as a moderator action). Note that this is different
  --   from deleting a comment.
  removeComment :: Monad m => CommentID -> RedditT m ()
  removeComment = nothing . runRoute . Route.removePost False
  