{-|
Module      : Init.hs
Description : Gargantext Init Script
Copyright   : (c) CNRS, 2017-Present
License     : AGPL + CECILL v3
Maintainer  : team@gargantext.org
Stability   : experimental
Portability : POSIX

Initialise the Gargantext dataset.

 -}

{-# LANGUAGE Strict            #-}

module CLI.Init where

import CLI.Parsers
import CLI.Types
import Data.List.NonEmpty qualified as NE
import Gargantext.API.Dev (withDevEnv, runCmdDev)
import Gargantext.API.Errors.Types
import Gargantext.API.Node () -- instances only
import Gargantext.Core.Config (GargConfig(..))
import Gargantext.Core.Config.Types (SecretsConfig(..))
import Gargantext.Core.Config.Utils (readConfig)
import Gargantext.Core.Types.Individu (User(..), arbitraryNewUsers, NewUser(..), arbitraryUsername, GargPassword(..))
import Gargantext.Database.Action.Flow (getOrMkRoot, getOrMkRootWithCorpus)
import Gargantext.Database.Admin.Trigger.Init (initFirstTriggers, initLastTriggers)
import Gargantext.Database.Admin.Types.Hyperdata (HyperdataCorpus)
import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Prelude
import Gargantext.Database.Query.Table.Node (getOrMkList)
import Gargantext.Database.Query.Table.User (insertNewUsers, )
import Gargantext.Database.Query.Tree.Root (MkCorpusUser(MkCorpusUserMaster))
import Gargantext.Prelude
import Options.Applicative
import Gargantext.Core.Types.Individu (toUserHash)


initCLI :: InitArgs -> IO ()
initCLI (InitArgs settingsPath) = do
  putStrLn ("Enter master user (gargantua) _password_ :" :: Text)
  password  <- getLine

  putStrLn ("Enter master user (gargantua) _email_ :" :: Text)
  email     <- getLine

  hashedUsers <- NE.fromList <$> mapM toUserHash (NewUser "gargantua" (cs email) (GargPassword $ cs password) : arbitraryNewUsers)

  cfg       <- readConfig         settingsPath
  let secret = _s_secret_key $ _gc_secrets cfg

  let createUsers :: DBUpdate BackendInternalError Int64
      createUsers = insertNewUsers hashedUsers

  let
    mkRoots :: DBUpdate BackendInternalError [(UserId, RootId)]
    mkRoots = mapM (getOrMkRoot cfg) $ map UserName ("gargantua" : arbitraryUsername)
    -- TODO create all users roots

  let
    initMaster :: DBUpdate BackendInternalError (UserId, RootId, CorpusId, ListId)
    initMaster = do
      (masterUserId, masterRootId, masterCorpusId)
                  <- getOrMkRootWithCorpus cfg MkCorpusUserMaster
                                            (Nothing :: Maybe HyperdataCorpus)
      masterListId <- getOrMkList masterCorpusId masterUserId
      _triggers    <- initLastTriggers masterListId
      pure (masterUserId, masterRootId, masterCorpusId, masterListId)

  withDevEnv settingsPath $ \env -> do
    x <- runCmdDev env $ runDBTx $ do
      _ <- initFirstTriggers secret
      _ <- createUsers
      x' <- initMaster
      _  <- mkRoots
      pure x'
    putStrLn (show x :: Text)

initCmd :: HasCallStack => Mod CommandFields CLI
initCmd = command "init" (info (helper <*> fmap CLISub init_p) (progDesc "Initialise this Gargantext instance."))

init_p :: Parser CLICmd
init_p = fmap CCMD_init $ InitArgs
  <$> settings_p
