{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

{- |
Module      :  GitHub.REST.Endpoint
Maintainer  :  Brandon Chinn <brandon@leapyear.io>
Stability   :  experimental
Portability :  portable

Define the 'GHEndpoint' helper type for defining a call to a GitHub API endpoint.
-}
module GitHub.REST.Endpoint (
  GHEndpoint (..),
  EndpointVals,
  GitHubData,
  endpointPath,
  renderMethod,
) where

import Data.Maybe (fromMaybe)

#if !MIN_VERSION_base(4,11,0)
import Data.Monoid ((<>))
#endif
import Data.Text (Text)
import qualified Data.Text as Text
import Network.HTTP.Types (Method, StdMethod, renderStdMethod)

import GitHub.REST.KeyValue (KeyValue, kvToText)

type EndpointVals = [KeyValue]
type GitHubData = [KeyValue]

-- | A call to a GitHub API endpoint.
data GHEndpoint = GHEndpoint
  { method :: StdMethod
  , -- | The GitHub API endpoint, with colon-prefixed components that will be replaced; e.g.
    -- @"\/users\/:username\/repos"@
    endpoint :: Text
  , -- | Key-value pairs to replace colon-prefixed components in 'endpoint'; e.g.
    -- @[ "username" := ("alice" :: Text) ]@
    endpointVals :: EndpointVals
  , -- | Key-value pairs to send in the request body; e.g.
    -- @[ "sort" := ("created" :: Text), "direction" := ("asc" :: Text) ]@
    ghData :: GitHubData
  }

-- | Return the endpoint path, populated by the values in 'endpointVals'.
endpointPath :: GHEndpoint -> Text
endpointPath GHEndpoint{..} = Text.intercalate "/" . map populate . Text.splitOn "/" $ endpoint
  where
    values = map kvToText endpointVals
    populate t = case Text.uncons t of
      Just (':', key) ->
        fromMaybe
          (fail' $ "Could not find value for key '" <> key <> "'")
          $ lookup key values
      _ -> t
    fail' msg = error . Text.unpack $ msg <> ": " <> endpoint

-- | Render the method of the endpoint.
renderMethod :: GHEndpoint -> Method
renderMethod = renderStdMethod . method
