{-|
Module      : Gargantext.API.GraphQL.User
Description :
Copyright   : (c) CNRS, 2017
License     : AGPL + CECILL v3
Maintainer  : team@gargantext.org
Stability   : experimental
Portability : POSIX
-}


{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DuplicateRecordFields #-}

module Gargantext.API.GraphQL.User where

import Data.Morpheus.Types ( GQLType )
import Gargantext.API.Admin.Auth.Types (AuthenticatedUser)
import Gargantext.API.Auth.PolicyCheck (AccessPolicyManager, nodeReadChecks)
import Gargantext.API.GraphQL.PolicyCheck (withPolicy)
import Gargantext.API.GraphQL.Types (GqlM, GqlM')
import Gargantext.Core.Types (NodeId(..), UserId)
import Gargantext.Core.Types.Individu qualified as Individu
import Gargantext.Database.Admin.Types.Hyperdata (HyperdataUser(..))
import Gargantext.Database.Prelude
import Gargantext.Database.Query.Table.User qualified as DBUser
import Gargantext.Database.Schema.User (UserLight(..))
import Gargantext.Prelude

data User m = User
  { u_email     :: Text
  , u_hyperdata :: m (Maybe HyperdataUser)
  , u_id        :: UserId
  , u_username  :: Text }
  deriving (Generic, GQLType)

-- | Arguments to the "user" query.
data UserArgs
  = UserArgs
    { user_id :: Int
    } deriving (Generic, GQLType)

data UserPubmedAPIKeyMArgs
  = UserPubmedAPIKeyMArgs
    { user_id :: Int
    , api_key  :: Text }
    deriving (Generic, GQLType)

data UserEPOAPIUserMArgs
  = UserEPOAPIUserMArgs
    { user_id  :: Int
    , api_user :: Text }
    deriving (Generic, GQLType)

data UserEPOAPITokenMArgs
  = UserEPOAPITokenMArgs
    { user_id   :: Int
    , api_token :: Text }
    deriving (Generic, GQLType)

-- | Function to resolve user from a query.
resolveUsers
  :: (IsDBEnvExtra env)
  => AuthenticatedUser
  -> AccessPolicyManager
  -> UserArgs
  -> GqlM e env [User (GqlM e env)]
resolveUsers autUser mgr UserArgs { user_id } = do
  -- We are given the /node id/ of the logged-in user.
  withPolicy autUser mgr (nodeReadChecks $ UnsafeMkNodeId user_id) $ dbUsers user_id

-- | Inner function to fetch the user from DB.
dbUsers :: (IsDBEnvExtra env)
        => Int -> GqlM e env [User (GqlM e env)]
dbUsers user_id = lift (map toUser <$> runDBQuery (DBUser.getUsersWithId (Individu.RootId $ UnsafeMkNodeId user_id)))

toUser
  :: (IsDBEnvExtra env)
  => UserLight -> User (GqlM e env)
toUser (UserLight { .. }) = User { u_email = userLight_email
                                 , u_hyperdata = resolveHyperdata userLight_id
                                 , u_id = userLight_id
                                 , u_username = userLight_username }

resolveHyperdata
  :: (IsDBEnvExtra env)
  => UserId -> GqlM e env (Maybe HyperdataUser)
resolveHyperdata userid = lift (listToMaybe <$> runDBQuery (DBUser.getUserHyperdata (Individu.UserDBId userid)))

updateUserPubmedAPIKey :: ( IsDBEnvExtra env ) =>
                          UserPubmedAPIKeyMArgs -> GqlM' e env Int
updateUserPubmedAPIKey UserPubmedAPIKeyMArgs { user_id, api_key } = do
  _ <- lift $ runDBTx $ DBUser.updateUserPubmedAPIKey (Individu.RootId $ UnsafeMkNodeId user_id) api_key

  pure 1

updateUserEPOAPIUser :: ( IsDBEnvExtra env ) =>
                        UserEPOAPIUserMArgs -> GqlM' e env Int
updateUserEPOAPIUser UserEPOAPIUserMArgs { user_id, api_user } = do
  _ <- lift $ runDBTx $ DBUser.updateUserEPOAPIUser (Individu.RootId $ UnsafeMkNodeId user_id) api_user

  pure 1

updateUserEPOAPIToken :: ( IsDBEnvExtra env ) =>
                         UserEPOAPITokenMArgs -> GqlM' e env Int
updateUserEPOAPIToken UserEPOAPITokenMArgs { user_id, api_token } = do
  _ <- lift $ runDBTx $ DBUser.updateUserEPOAPIToken (Individu.RootId $ UnsafeMkNodeId user_id) api_token

  pure 1
