{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Utils.ThankYouStars.GitHub (
      Token(..)
    , GitHubRepo(..)
    , readToken
    , starRepo
    ) where

import           Control.Exception     ( catch, throwIO )
import           Data.Aeson
import           Data.ByteString       ( ByteString )
import qualified Data.ByteString.Lazy  as BSL
import           Data.Monoid           ( (<>) )
import           Data.String           ( fromString )
import           Data.Text.Encoding    ( encodeUtf8 )
import           Data.Version          ( showVersion )
import           Network.HTTP.Req
import           Paths_thank_you_stars ( version )

data Token = Token {
      unToken :: ByteString
    } deriving ( Eq, Show )

instance FromJSON Token where
    parseJSON (Object v) = Token . encodeUtf8 <$> v .: "token"

readToken :: FilePath -> IO (Either String Token)
readToken fp = eitherDecode <$> BSL.readFile fp

data GitHubRepo = GitHubRepo {
      owner    :: String
    , repo     :: String
    } deriving ( Eq, Ord )

instance Show GitHubRepo where
    show ghr = "https://github.com/" ++ owner ghr ++ "/" ++ repo ghr

starringUrl :: GitHubRepo -> Url 'Https
starringUrl ghr =
    https "api.github.com" /: "user" /: "starred" /~ owner ghr /~ repo ghr

userAgent :: Option scheme
userAgent = header "User-Agent" agent
    where
        agent = "thank-you-stars/" <> fromString (showVersion version)

instance MonadHttp IO where
    handleHttpException = throwIO

starRepo :: Token -> GitHubRepo -> IO (Either HttpException ())
starRepo token ghr =
    (do
            let headers = oAuth2Token (unToken token) <> userAgent
            _ <- req PUT (starringUrl ghr) NoReqBody ignoreResponse headers
            return $ Right ()
        ) `catch` (\(e :: HttpException) -> do
            return $ Left e
        )