{-|
Module      : Gargantext.API.Node.Corpus.Export
Description : Corpus export
Copyright   : (c) CNRS, 2017-Present
License     : AGPL + CECILL v3
Maintainer  : team@gargantext.org
Stability   : experimental
Portability : POSIX

Main exports of Gargantext:
- corpus
- document and ngrams
- lists
-}

module Gargantext.API.Node.Corpus.Export
  where

import Control.Exception.Safe qualified as CES
import Control.Lens (view)
import Data.List qualified as List
import Data.Map.Strict qualified as Map
import Data.Set qualified as Set
import Data.Text (pack)
import Gargantext.API.Ngrams.Tools (getRepo)
import Gargantext.API.Ngrams.Types ( NgramsTerm(unNgramsTerm) )
import Gargantext.API.Node.Corpus.Export.Types ( Corpus(..), CorpusSQLite(..) )
import Gargantext.API.Node.Corpus.Export.Utils (getContextNgrams, mkCorpusSQLite, mkCorpusSQLiteData)
import Gargantext.API.Node.Document.Export.Types qualified as DocumentExport
import Gargantext.API.Prelude (IsGargServer)
import Gargantext.API.Routes.Named.Corpus qualified as Named
import Gargantext.Core.NodeStory
import Gargantext.Core.Text.Ngrams (NgramsType(..))
import Gargantext.Core.Types.Main ( ListType(MapTerm) )
import Gargantext.Database.Admin.Types.Hyperdata.Document ( HyperdataDocument(..) )
import Gargantext.Database.Admin.Types.Node (Context, CorpusId, ListId, context2node, nodeId2ContextId)
import Gargantext.Database.Prelude
import Gargantext.Database.Query.Table.Node ( defaultList )
import Gargantext.Database.Query.Table.NodeContext (selectDocNodes)
import Gargantext.Database.Schema.Context (_context_id)
import Gargantext.Prelude hiding (hash)
import Gargantext.Prelude.Crypto.Hash (hash)
import Servant (Headers, Header, addHeader)
import Servant.Server.Generic (AsServerT)

--------------------------------------------------
-- | Hashes are ordered by Set
getCorpus :: (CES.MonadMask m, IsGargServer env err m)
          => CorpusId
          -> Named.CorpusExportAPI (AsServerT m)
getCorpus cId = Named.CorpusExportAPI {
    Named.corpusExportEp = get_corpus
  , Named.corpusSQLiteEp = getCorpusSQLite cId
  }

  where
    get_corpus :: IsGargServer env err m
               => Maybe ListId
               -> Maybe NgramsType
               -> m (Headers '[Header "Content-Disposition" Text] Corpus)
    get_corpus lId nt' = do
      env <- view hasNodeStory
      runDBQuery $ do
        let
          nt = fromMaybe NgramsTerms nt'

        listId <- case lId of
          Nothing -> defaultList cId
          Just l  -> pure l

        -- FIXME(adn) Audit the usage of this, we are converting from a node
        -- to a context id.
        ns   <- Map.fromList
             <$> map (\n -> (nodeId2ContextId $ _context_id n, n))
             <$> selectDocNodes cId

        repo <- getRepo env [listId]
        ngs  <- getContextNgrams cId listId MapTerm nt repo
        let  -- uniqId is hash computed already for each document imported in database
          r = Map.intersectionWith
              (\a b -> DocumentExport.Document { _d_document = context2node a
                                               , _d_ngrams = DocumentExport.Ngrams (Set.toList b) (hash b)
                                               , _d_hash = d_hash a b }
              ) ns (Map.map (Set.map unNgramsTerm) ngs)
                where
                  d_hash :: Context HyperdataDocument -> Set Text -> Text
                  d_hash  _a b = hash [ -- fromMaybe "" (_hd_uniqId $ _context_hyperdata a),
                                      hash b
                                     ]
        pure $ addHeader ("attachment; filename=GarganText_corpus-" <> pack (show cId) <> ".json")
          $ Corpus { _c_corpus = Map.elems r
                   , _c_hash = hash $ List.map DocumentExport._d_hash $ Map.elems r }


getCorpusSQLite :: ( CES.MonadMask m
                   , IsGargServer env err m)
                  => CorpusId
                  -> Maybe ListId
                  -> m (Headers '[Header "Content-Disposition" Text] CorpusSQLite)
getCorpusSQLite cId lId = do
  corpusSQLiteData <- mkCorpusSQLiteData cId lId
  corpusSQLite <- mkCorpusSQLite corpusSQLiteData
  pure $ addHeader ("attachment; filename=GarganText_corpus-" <> pack (show cId) <> ".sqlite")
    $ corpusSQLite

-- TODO
-- Exports List
-- Version number of the list
