{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
#if __GLASGOW_HASKELL__ >= 800
{-# OPTIONS_GHC -Wno-missing-signatures #-}
#else
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
#endif
module Database.InfluxDB.Ping
  ( 
    ping
  
  , PingParams
  , pingParams
  , server
  , manager
  , timeout
  
  , Pong
  , roundtripTime
  , influxdbVersion
  ) where
import Control.Exception
import Control.Lens
import Data.Time.Clock (NominalDiffTime)
import System.Clock
import qualified Data.ByteString as BS
import qualified Data.Text.Encoding as TE
import qualified Network.HTTP.Client as HC
import Database.InfluxDB.Types as Types
data PingParams = PingParams
  { pingServer :: !Server
  , pingManager :: !(Either HC.ManagerSettings HC.Manager)
  
  , pingTimeout :: !(Maybe NominalDiffTime)
  
  }
pingParams :: PingParams
pingParams = PingParams
  { pingServer = defaultServer
  , pingManager = Left HC.defaultManagerSettings
  , pingTimeout = Nothing
  }
makeLensesWith
  ( lensRules
    & generateSignatures .~ False
    & lensField .~ lookingupNamer
      [ ("pingServer", "_server")
      , ("pingManager", "_manager")
      , ("pingTimeout", "timeout")
      ]
    )
  ''PingParams
instance HasServer PingParams where
  server = _server
instance HasManager PingParams where
  manager = _manager
timeout :: Lens' PingParams (Maybe NominalDiffTime)
pingRequest :: PingParams -> HC.Request
pingRequest PingParams {..} = HC.defaultRequest
  { HC.host = TE.encodeUtf8 _host
  , HC.port = fromIntegral _port
  , HC.secure = _ssl
  , HC.method = "GET"
  , HC.path = "/ping"
  }
  where
    Server {..} = pingServer
data Pong = Pong
  { _roundtripTime :: !TimeSpec
  
  , _influxdbVersion :: !BS.ByteString
  
  } deriving (Show, Eq, Ord)
makeLensesWith (lensRules & generateSignatures .~ False) ''Pong
roundtripTime :: Lens' Pong TimeSpec
influxdbVersion :: Lens' Pong BS.ByteString
ping :: PingParams -> IO Pong
ping params = do
  manager' <- either HC.newManager return $ pingManager params
  startTime <- getTimeMonotonic
  HC.withResponse request manager' $ \response -> do
    endTime <- getTimeMonotonic
    case lookup "X-Influxdb-Version" (HC.responseHeaders response) of
      Just version ->
        return $! Pong (diffTimeSpec endTime startTime) version
      Nothing ->
        throwIO $ UnexpectedResponse
          "The X-Influxdb-Version header was missing in the response."
          request
          ""
  `catch` (throwIO . HTTPException)
  where
    request = (pingRequest params)
      { HC.responseTimeout = case pingTimeout params of
        Nothing -> HC.responseTimeoutNone
        Just sec -> HC.responseTimeoutMicro $
          round $ realToFrac sec / (10**(-6) :: Double)
      }
    getTimeMonotonic = getTime Monotonic