{- This file is part of funbot-client.
 -
 - Written in 2015 by fr33domlover <fr33domlover@rel4tion.org>.
 -
 - ♡ Copying is an act of love. Please copy, reuse and share.
 -
 - The author(s) have dedicated all copyright and related and neighboring
 - rights to this software to the public domain worldwide. This software is
 - distributed without any warranty.
 -
 - You should have received a copy of the CC0 Public Domain Dedication along
 - with this software. If not, see
 - <http://creativecommons.org/publicdomain/zero/1.0/>.
 -}

-- | Using this module, you can send external events (such as git commits) to a
-- running FunBot instance over HTTP.
--
-- Constructing events requires using types from the @funbot-ext-events@
-- package. But you should not use the @ExtEvent@ constructors from there,
-- because if they change, it will break your code. Instead, use the functions
-- provided below. This way new events can be added without breaking old code.
module FunBot.Client
    ( Bot ()
    , ExtEvent ()
    , mkBot
    , sendExtEvent
    , mkPushEvent
    , mkTagEvent
    , mkMergeRequestEvent
    , mkNewsEvent
    , mkPasteEvent
    )
where

import Data.Aeson (encode)
import Data.Aeson.Encode.Pretty (encodePretty)
import FunBot.ExtEvents
import Network.HTTP
import Network.Stream (ConnError)
import Network.URI (URI)

import qualified Data.ByteString.Lazy as B

-- | Reference to running FunBot instance to which you can send events.
newtype Bot = Bot
    { botMkRequest :: ExtEvent -> Request B.ByteString
    }

-- | Create a reference to a FunBot instance.
--
-- You can parse the URL at runtime using 'Network.URI.parseURI' or at compile
-- time using 'Network.URI.Static.staticURI' (or the @uri@ quasi quoter in the
-- same package).
mkBot :: URI  -- ^ URL at which the bot listens to client events.
      -> Bool -- ^ Whether JSON data should be sent in pretty form, i.e.
              -- indented. This may be useful for debugging, but otherwise you
              -- should probably pass 'False' here.
      -> Bot
mkBot uri pretty =
    let f event =
            let body = if pretty then encodePretty event else encode event
            in  Request
                    { rqURI     = uri
                    , rqBody    = body
                    , rqHeaders =
                        [ Header HdrContentType "application/json"
                        , Header HdrContentLength (show $ B.length body)
                        ]
                    , rqMethod  = POST
                    }
    in  Bot f

-- | Send an event to a bot over HTTP. If successfully sent, return 'Nothing'.
-- If an error occurs, return 'Just' the error details.
sendExtEvent :: Bot -> ExtEvent -> IO (Maybe ConnError)
sendExtEvent bot event = do
    result <- simpleHTTP $ botMkRequest bot event
    case result of
        Left err -> return $ Just err
        Right _  -> return Nothing

-- | Construct a git push event.
mkPushEvent :: Push -> ExtEvent
mkPushEvent = GitPushEvent

-- | Construct a git tag event.
mkTagEvent :: Tag -> ExtEvent
mkTagEvent = GitTagEvent

-- | Construct a merge request event.
mkMergeRequestEvent :: MergeRequest -> ExtEvent
mkMergeRequestEvent = MergeRequestEvent

-- | Construct a news item event.
mkNewsEvent :: NewsItem -> ExtEvent
mkNewsEvent = NewsEvent

-- | Construct a paste event.
mkPasteEvent :: Paste -> ExtEvent
mkPasteEvent = PasteEvent