fetchNewComments :: MonadIO m => Options -> CommentProducer m
fetchNewComments opts@Options{..} = do
  -- Only authenticated users can watch the stream of all new Reddit comments
  if isNothing optCredentials && isJust optSubreddit then do
    logAt Warn "Cannot fetch /comments from the entire Reddit unless logged in"
    return $ Left (APIError CredentialsError)
  else do
    logAt Debug $ "Fetching new comments from " <>
      maybe "the entire Reddit" (("subreddit: " <>) . tshow) optSubreddit
    doFetch opts Nothing
  where
  doFetch :: MonadIO m => Options -> Maybe CommentID -> CommentProducer m
  doFetch opts after = do
    result <- runReddit opts $ do
      let fetchOpts = newFetchOptions opts after
      Listing _ after' comments <- getNewComments' fetchOpts optSubreddit
      logFmt Debug "Received {} new comments (after = {})"
                   (length comments, tshow after)
      return (comments, after')
    case result of
      Left err -> return $ Left err
      Right (comments, after') -> do
        mapM_ yield comments
        let isEmpty = null comments && isNothing after -- not after'
        if isEmpty then return $ Right ()
        else do
          -- Sleep for 1 second, as per Reddit API recommendation,
          -- or for longer if we exhausted the listing
          -- (as it likely means starting from the beginning of it,
          --  i.e. completely new posts)
          delaySecs <- case after' of
            Just _ -> do
              logAt Trace "Sleeping for a second before continuing with fetch"
              return 1
            Nothing -> do
              logAt Debug $ "Exhausted the comment listing, starting over in "
                            <> tshow restartDelaySecs <> " seconds"
              return restartDelaySecs
          liftIO $ threadDelay (delaySecs * 1000000)
          doFetch opts after'

  restartDelaySecs = 5
fetchNewComments :: MonadIO m => Options -> CommentProducer m
fetchNewComments opts@Options{..} = do
  -- Only authenticated users can watch the stream of all new Reddit comments
  if isNothing optCredentials && isJust optSubreddit then do
    logAt Warn "Cannot fetch /comments from the entire Reddit unless logged in"
    return $ Left (APIError CredentialsError)
  else do
    logAt Debug $ "Fetching new comments from " <>
      maybe "the entire Reddit" (("subreddit: " <>) . tshow) optSubreddit
    doFetch opts Nothing
  where
  doFetch :: MonadIO m => Options -> Maybe CommentID -> CommentProducer m
  doFetch opts after = do
    result <- runReddit opts $ do
      let fetchOpts = newFetchOptions opts after
      Listing _ after' comments <- getNewComments' fetchOpts optSubreddit
      logFmt Debug "Received {} new comments (after = {})"
                   (length comments, tshow after)
      return (comments, after')
    case result of
      Left err -> return $ Left err
      Right (comments, after') -> do
        mapM_ yield comments
        let isEmpty = null comments && isNothing after -- not after'
        if isEmpty then return $ Right ()
        else do
          -- Sleep for 1 second, as per Reddit API recommendation,
          -- or for longer if we exhausted the listing
          -- (as it likely means starting from the beginning of it,
          --  i.e. completely new posts)
          delaySecs <- case after' of
            Just _ -> do
              logAt Trace "Sleeping for a second before continuing with fetch"
              return 1
            Nothing -> do
              logAt Debug $ "Exhausted the comment listing, starting over in "
                            <> tshow restartDelaySecs <> " seconds"
              return restartDelaySecs
          liftIO $ threadDelay (delaySecs * 1000000)
          doFetch opts after'

  restartDelaySecs = 5
fetchNewComments opts@Options{..} = do
  -- Only authenticated users can watch the stream of all new Reddit comments
  if isNothing optCredentials && isJust optSubreddit then do
    logAt Warn "Cannot fetch /comments from the entire Reddit unless logged in"
    return $ Left (APIError CredentialsError)
  else do
    logAt Debug $ "Fetching new comments from " <>
      maybe "the entire Reddit" (("subreddit: " <>) . tshow) optSubreddit
    doFetch opts Nothing
  where
  doFetch :: MonadIO m => Options -> Maybe CommentID -> CommentProducer m
  doFetch opts after = do
    result <- runReddit opts $ do
      let fetchOpts = newFetchOptions opts after
      Listing _ after' comments <- getNewComments' fetchOpts optSubreddit
      logFmt Debug "Received {} new comments (after = {})"
                   (length comments, tshow after)
      return (comments, after')
    case result of
      Left err -> return $ Left err
      Right (comments, after') -> do
        mapM_ yield comments
        let isEmpty = null comments && isNothing after -- not after'
        if isEmpty then return $ Right ()
        else do
          -- Sleep for 1 second, as per Reddit API recommendation,
          -- or for longer if we exhausted the listing
          -- (as it likely means starting from the beginning of it,
          --  i.e. completely new posts)
          delaySecs <- case after' of
            Just _ -> do
              logAt Trace "Sleeping for a second before continuing with fetch"
              return 1
            Nothing -> do
              logAt Debug $ "Exhausted the comment listing, starting over in "
                            <> tshow restartDelaySecs <> " seconds"
              return restartDelaySecs
          liftIO $ threadDelay (delaySecs * 1000000)
          doFetch opts after'

  restartDelaySecs = 5