{-# LANGUAGE OverloadedStrings #-}

module Rest where

import Network.HTTP.Conduit
import Control.Applicative
import Network.HTTP.Types
import qualified Data.ByteString.Char8 as C8
import qualified Data.ByteString.Lazy.Char8 as LC8
import Data.String (fromString)
import Data.Digest.Pure.SHA
import Data.Time.Format
import Data.Time.Clock
import System.Locale
import Data.Char
import qualified Data.Yaml as Y
import Data.Aeson
import Control.Monad (mzero)

data SortOrder = Asc | Desc
instance Show SortOrder where
  show Asc = "asc"
  show Desc = "desc"
  
data Config = Config { apiSecret :: String, apiKey :: String, clientId :: String }

instance FromJSON Config where
  parseJSON (Object obj) = Config <$> 
    ((obj .: "production") >>= (.: "apiSecret")) <*>
    ((obj .: "production") >>= (.: "apiKey")) <*>
    ((obj .: "production") >>= (.: "clientId"))

  parseJSON _ = mzero

baseUrl :: String
baseUrl = "https://www.bitstamp.net/api"

post :: String -> [(C8.ByteString, C8.ByteString)] -> IO (Response LC8.ByteString)
post endpoint qParams = do
  nonce <- getNonce

  Just config <- getConfigData
  let apiSecret' = apiSecret config
  let clientId' = clientId config
  let apiKey' = apiKey config

  let signature = map toUpper $ showDigest $ hmacSha256 (fromString apiSecret') 
                                                        (fromString $ nonce ++ clientId' ++ apiKey') 

  let authParams = [(fromString "key", fromString apiKey'), 
                    (fromString "nonce", fromString nonce), 
                    (fromString "signature", fromString signature)]

  request <- parseUrl $ baseUrl ++ endpoint
  withManager $ httpLbs $ urlEncodedBody (authParams ++ qParams) $ request { method = methodPost }
  where
    getNonce :: IO String
    getNonce = getCurrentTime >>= return . formatTime defaultTimeLocale "%s"

get :: String -> [(C8.ByteString, Maybe C8.ByteString)] -> IO (Response LC8.ByteString)
get endpoint qParams = do
  request <- parseUrl endpoint
  withManager $ httpLbs request { method = methodGet, queryString = renderQuery True qParams }

getConfigData :: IO (Maybe Config)
getConfigData = Y.decodeFile "src/config.yml" :: IO (Maybe Config)