module Jobs.Handler.SynchroniseLdap
  ( dispatchJobSynchroniseLdap, dispatchJobSynchroniseLdapUser
  , SynchroniseLdapException(..)
  ) where

import Import

import qualified Data.Conduit.List as C

import Auth.LDAP

import Jobs.Queue
  

data SynchroniseLdapException
  = SynchroniseLdapNoLdap
  deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable)
instance Exception SynchroniseLdapException

dispatchJobSynchroniseLdap :: Natural -> Natural -> Natural -> Handler ()
dispatchJobSynchroniseLdap numIterations epoch iteration
  = runDBJobs . runConduit $
      readUsers .| filterIteration .| sinkDBJobs
  where
    readUsers :: ConduitT () UserId (YesodJobDB UniWorX) ()
    readUsers = selectKeys [] []

    filterIteration :: ConduitT UserId Job (YesodJobDB UniWorX) ()
    filterIteration = C.mapMaybeM $ \userId -> runMaybeT $ do
      let
        userIteration, currentIteration :: Integer
        userIteration = toInteger (hash epoch `hashWithSalt` userId) `mod` toInteger numIterations
        currentIteration = toInteger iteration `mod` toInteger numIterations
      $logDebugS "SynchroniseLdap" [st|User ##{tshow (fromSqlKey userId)}: sync on #{tshow userIteration}/#{tshow numIterations}, now #{tshow currentIteration}|]
      guard $ userIteration == currentIteration

      return $ JobSynchroniseLdapUser userId

dispatchJobSynchroniseLdapUser :: UserId -> Handler ()
dispatchJobSynchroniseLdapUser jUser = do
  UniWorX{ appSettings' = AppSettings{..}, .. } <- getYesod
  case (,) <$> appLdapConf <*> appLdapPool of
    Just (ldapConf, ldapPool) -> 
      runDB . void . runMaybeT . handleExc $ do
        user@User{userIdent} <- MaybeT $ get jUser

        $logInfoS "SynchroniseLdap" [st|Synchronising #{userIdent}|]

        ldapAttrs <- MaybeT $ campusUser' ldapConf ldapPool user
        void . lift $ upsertCampusUser UpsertCampusUser ldapAttrs
    Nothing ->
      throwM SynchroniseLdapNoLdap
  where
    handleExc
      = catchMPlus (Proxy @CampusUserException)
      . catchMPlus (Proxy @CampusUserConversionException)
