{-# LANGUAGE ScopedTypeVariables  #-}
{-# LANGUAGE TypeApplications     #-}
{-# LANGUAGE TypeOperators        #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Gargantext.API.Server.Named.EKG where

import Data.HashMap.Strict as HM
import Data.Text as T
import Data.Text.IO as T
import Data.Time.Clock.POSIX (getPOSIXTime)
import Gargantext.API.Routes.Named.EKG (EkgAPI(..))
import Network.Wai (Middleware)
import Protolude
import Servant
import Servant.Auth (Auth)
import Servant.Ekg (HasEndpoint, enumerateEndpoints, getEndpoint, monitorEndpoints)
import Servant.Server.Generic (AsServer)
import System.Metrics (Store, newStore, registerCounter, registerGcMetrics, sampleAll)
import System.Metrics.Json qualified as J


ekgServer :: FilePath -> Store -> EkgAPI AsServer
ekgServer assetsDir store = EkgAPI
  { ekgAPI = (getAll :<|> getOne) :<|> serveDirectoryFileServer assetsDir }

  where getAll = J.Sample <$> liftIO (sampleAll store)
        getOne segments = do
          let metric = T.intercalate "." segments
          metrics <- liftIO (sampleAll store)
          maybe (liftIO (T.putStrLn "not found boohoo") >> throwError err404) (return . J.Value) (HM.lookup metric metrics)


newEkgStore :: HasEndpoint api => Proxy api -> IO (Store, Middleware)
newEkgStore api = do
  s <- newStore
  registerGcMetrics s
  registerCounter "ekg.server_timestamp_ms" getTimeMs s -- used by UI
  mid <- monitorEndpoints api s
  pure (s, mid)

  where getTimeMs = (round . (* 1000)) `fmap` getPOSIXTime

instance HasEndpoint api => HasEndpoint (Auth xs a :> api) where
    getEndpoint        _ = getEndpoint        (Proxy :: Proxy api)
    enumerateEndpoints _ = enumerateEndpoints (Proxy :: Proxy api)

instance HasEndpoint (ToServant api AsApi) => HasEndpoint (NamedRoutes api) where
    getEndpoint        _ = getEndpoint        (Proxy @(ToServant api AsApi))
    enumerateEndpoints _ = enumerateEndpoints (Proxy @(ToServant api AsApi))
