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

import Tonalude

import qualified Google.Client as Client
import qualified Google.Form as Form
import Google.JWT (JWT)
import qualified Google.JWT as JWT
import Google.Response (Token)
import qualified Google.Response as Response
import Servant.Client (ServantError)

import Tonatona (HasConfig(..), HasParser(..))
import TonaParser (Parser, (.||), argLong, envVar, liftWith, 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