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


{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE MonoLocalBinds      #-}

module Gargantext.API.Node.FrameCalcUpload where

import Control.Exception.Safe (MonadMask)
import Data.ByteString.Lazy qualified as BSL
import Data.Text qualified as T
import Database.PostgreSQL.Simple.LargeObjects qualified as PSQL
import Gargantext.API.Admin.Auth.Types ( auth_node_id, AuthenticatedUser )
import Gargantext.API.Admin.EnvTypes (Env)
import Gargantext.API.Errors.Types ( BackendInternalError )
import Gargantext.API.Node.Corpus.New (addToCorpusWithTempFile)
import Gargantext.API.Node.Corpus.New.Types (FileFormat(..), FileType(..))
import Gargantext.API.Node.FrameCalcUpload.Types ( FrameCalcUpload(FrameCalcUpload) )
import Gargantext.API.Node.Types (NewWithTempFile(..))
import Gargantext.API.Prelude ( GargM )
import Gargantext.API.Routes.Named.FrameCalc qualified as Named
import Gargantext.API.Worker (serveWorkerAPI)
import Gargantext.Core.Config (HasConfig)
import Gargantext.Core.Types.Individu (User(..))
import Gargantext.Core.Worker.Jobs.Types qualified as Jobs
import Gargantext.Database.Action.Flow.Types ( FlowCmdM )
import Gargantext.Database.Admin.Types.Hyperdata.Frame ( HyperdataFrame(..) )
import Gargantext.Database.Admin.Types.Node ( NodeId, NodeType(NodeCorpus) )
import Gargantext.Database.Query.Table.Node (getClosestParentIdByType, getNodeWith)
import Gargantext.Database.Prelude
import Gargantext.Database.Schema.Node (node_hyperdata)
import Gargantext.Prelude
import Gargantext.Utils.Jobs.Monad (MonadJobStatus(..), markFailureNoErr)
import Network.HTTP.Client (newManager, httpLbs, parseRequest, responseBody)
import Network.HTTP.Client.TLS (tlsManagerSettings)
import Servant.Server.Generic (AsServerT)


api :: AuthenticatedUser -> NodeId -> Named.FrameCalcAPI (AsServerT (GargM Env BackendInternalError))
api authenticatedUser nId =
  Named.FrameCalcAPI {
    frameCalcUploadEp = serveWorkerAPI $ \p ->
        Jobs.FrameCalcUpload { _fca_args = p
                             , _fca_authenticatedUser = authenticatedUser
                             , _fca_node_id = nId }
  }



frameCalcUploadAsync :: ( MonadMask m
                        , HasConfig env
                        , FlowCmdM env err m
                        , MonadJobStatus m
                        )
                     => AuthenticatedUser
                     -- ^ The logged-in user
                     -> NodeId
                     -> FrameCalcUpload
                     -> JobHandle m
                     -> m ()
frameCalcUploadAsync authenticatedUser nId (FrameCalcUpload _wtf_lang _wtf_selection) jobHandle = do
  markStarted 5 jobHandle

  -- printDebug "[frameCalcUploadAsync] uId" uId
  -- printDebug "[frameCalcUploadAsync] nId" nId

  node <- runDBQuery $ getNodeWith nId (Proxy :: Proxy HyperdataFrame)
  let (HyperdataFrame { _hf_base = base
                      , _hf_frame_id = frame_id }) = node ^. node_hyperdata

  let csvUrl = base <> "/" <> frame_id <> ".csv"
  -- printDebug "[frameCalcUploadAsync] csvUrl" csvUrl

  res <- liftBase $ do
    manager <- newManager tlsManagerSettings
    req <- parseRequest $ T.unpack csvUrl
    httpLbs req manager
  let body = BSL.toStrict $ responseBody res
  PSQL.Oid oId <- createLargeObject body

  -- printDebug "body" body
  mCId <- runDBQuery $ getClosestParentIdByType nId NodeCorpus
  -- printDebug "[frameCalcUploadAsync] mCId" mCId

  case mCId of
    Nothing -> markFailureNoErr 1 jobHandle
    Just cId ->
      -- FIXME(adn) Audit this conversion.
      addToCorpusWithTempFile (RootId userNodeId)
                              cId
                              (NewWithTempFile { _wtf_filetype = TSV
                                               , _wtf_fileformat = Plain
                                               , _wtf_file_oid = fromIntegral oId
                                               , _wtf_lang
                                               , _wtf_name = "calc-upload.csv"
                                               , _wtf_selection }) jobHandle

  markComplete jobHandle
  where
    userNodeId = authenticatedUser ^. auth_node_id
