{-# LANGUAGE CPP #-}
module Tonatona.Google
  ( run
  , Dsl
  , DslBackend
  , Config
  , ClientError
  , JWT
  , JWT.Scope(..)
  ) where

import Tonalude

import qualified Google.Client as Client
import Google.JWT (JWT)
import qualified Google.JWT as JWT
#if MIN_VERSION_servant_client(0, 16, 0)
import Servant.Client (ClientError)
#else
import Servant.Client (ServantError)
#endif

import Tonatona (HasConfig(..), HasParser(..))
import TonaParser (Parser, (.||), argLong, envVar, requiredVal)
import Tonatona.Google.Internal

#if !MIN_VERSION_servant_client(0, 16, 0)
type ClientError = ServantError
#endif

-- | Main function.
run ::
     (HasConfig env Config)
  => (ClientError -> RIO env a)
  -- ^ Error handler
  -> [JWT.Scope]
  -> Dsl env a
  -> RIO env a
run errorHandler scopes query = do
  Config {..} <- asks config
  eToken <- liftIO $ Client.getToken (Just delegationEmail) jwt scopes
  case eToken of
    Left err -> errorHandler err
    Right token ->
      runReaderT query (DslBackend token) `catch` errorHandler


------------
-- Config --
------------

data Config = Config
  { serviceKeyFile :: ServiceKeyFile
  , jwt :: JWT
  , delegationEmail :: JWT.Email
  }

newtype ServiceKeyFile = ServiceKeyFile { unServiceKeyFile :: FilePath }
  deriving (Eq, Read, Show)

instance HasParser ServiceKeyFile where
  parser = ServiceKeyFile <$>
    requiredVal
      "File path to service key file (Example: \"gmail-3abc452de.json\")"
      ( argLong "service-key-file" .|| envVar "SERVICE_KEY_FILE")

parseJwt :: ServiceKeyFile -> Parser JWT
parseJwt (ServiceKeyFile fp) = do
  mjwt <- liftIO $ JWT.readServiceKeyFile fp
  case mjwt of
    Nothing ->
      error $ "Failed to parse service key file: " <> fp
    Just jwt ->
      pure jwt

parseEmail :: Parser JWT.Email
parseEmail = JWT.Email <$>
  requiredVal
    "Email account to use for delegation."
    ( argLong "delegation-email" .|| envVar "DELEGATION_EMAIL")

instance HasParser Config where
  parser = do
    keyFile <- parser
    Config
      <$> pure keyFile
      <*> parseJwt keyFile
      <*> parseEmail