module Tonatona.Google
  ( run
  , Dsl
  , DslBackend
  , Config
  , ServantError
  , JWT
  , JWT.Scope(..)
  ) where

import Tonalude

import qualified Google.Client as Client
import Google.JWT (JWT)
import qualified Google.JWT as JWT
import Servant.Client (ServantError)

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

-- | Main function.
run ::
     (HasConfig env Config)
  => (ServantError -> 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