-- | Various utilities to tweet using the twitter api
--
-- Make sure you have a file credentials file (default the executable looks for is @$HOME/.cred.toml@) with the following info:
--
-- @
--
-- api-key = "API_KEY"
--
-- api-sec = "API_SECRET"
--
-- tok = "OAUTH_TOKEN"
--
-- tok-sec = "TOKEN_SECRET"
--
-- @

module Web.Tweet
    (
    -- * Functions to tweet
      basicTweet
    , thread
    , reply
    -- * Data type for a tweet
    , module Web.Tweet.Types
    -- * Various API calls
    , module Web.Tweet.API
    , module Web.Tweet.API.Internal
    -- * Functions to sign API requests
    , signRequest
    , oAuthMem
    , credentialMem
    -- * Functions to generate a URL string from a `Tweet`
    , urlString
    -- * Timeline filters
    , filterReplies
    , filterRTs
    , filterQuotes
    -- * Helper function to print a bird
    , bird
    ) where

import           Control.Monad
import           Data.Default
import           Data.List.Split        (chunksOf)
import           Data.Maybe
import           Lens.Micro
import           Web.Tweet.API
import           Web.Tweet.API.Internal
import           Web.Tweet.Sign
import           Web.Tweet.Types
import           Web.Tweet.Utils
import           Web.Tweet.Utils.API

-- | Tweet a string given a path to credentials; return the id of the status.
--
-- > basicTweet "On the airplane." ".cred"
basicTweet :: String -> FilePath -> IO Int
basicTweet contents = tweetData (mkTweet contents)

-- | thread tweets together nicely. Takes a string, a list of handles to reply to, plus the ID of the status you're replying to.
-- If you need to thread tweets without replying, pass a `Nothing` as the third argument.
--
-- > thread "Hi I'm back in New York!" ["friend1","friend2"] Nothing 1 ".cred"
thread :: String -> [String] -> Maybe Int -> Int -> FilePath -> IO ()
thread contents hs idNum num filepath = do
    let handleStr = concatMap ((++) " " . (++) "@") hs
    let content = take num . chunksOf (280-length handleStr) $ contents
    case idNum of
        (Just _) -> thread' content hs idNum filepath
        Nothing -> case content of
            []      -> pure ()
            [x]     -> void $ basicTweet x filepath
            y@(_:_) -> thread' y hs (Just 0) filepath

-- | Helper function to make `thread` easier to write.
thread' :: [String] -> [String] -> Maybe Int -> FilePath -> IO ()
thread' content hs idNum filepath = do
    let f str i = tweetData Tweet { _status = str, _handles = hs, _replyID = if i == 0 then Nothing else Just i } filepath
    let initial = f (head content)
    lastTweet <- foldr ((>=>) . f) initial content $ fromMaybe 0 idNum
    deleteTweet (fromIntegral lastTweet) filepath

-- | Reply with a single tweet. Works the same as `thread` but doesn't take the fourth argument.
--
-- > reply "Idk what that means" ["friend1"] (Just 189943500) ".cred"
reply :: String -> [String] -> Maybe Int -> FilePath -> IO ()
reply contents hs idNum = thread contents hs idNum 1

-- | Make a `Tweet` with only the contents.
mkTweet :: String -> Tweet
mkTweet contents = over status (const contents) def