
module Gargantext.API.Server.Named.Public (
  serverPublicGargAPI
  ) where

import Control.Lens ((^?), _Just)
import Data.List qualified as List
import Data.Map.Strict qualified as Map
import Data.Set qualified as Set
import Gargantext.API.Node.File (fileApi)
import Gargantext.API.Prelude (serverError, IsGargServer)
import Gargantext.API.Public.Types
import Gargantext.Core.Utils.DateUtils (utc2year)
import Gargantext.Database.Admin.Types.Hyperdata.Corpus ( hc_fields )
import Gargantext.Database.Admin.Types.Hyperdata.CorpusField
import Gargantext.Database.Admin.Types.Hyperdata.Folder ( HyperdataFolder )
import Gargantext.Database.Admin.Types.Node ( NodeId(..), Node, unNodeId )
import Gargantext.Database.Prelude (Cmd, DBCmd)
import Gargantext.Database.Query.Table.Node.Error (HasNodeError(..))
import Gargantext.Database.Query.Table.NodeNode (selectPublicNodes)
import Gargantext.Database.Schema.Node ( NodePoly(..), node_date, node_hyperdata ) -- (NodePoly(..))
import Gargantext.Prelude
import Servant
import Servant.Server.Generic (AsServerT)
import qualified Gargantext.API.Routes.Named.File as Named
import qualified Gargantext.API.Routes.Named.Public as Named

serverPublicGargAPI :: IsGargServer env err m => Text -> Named.GargPublicAPI (AsServerT m)
serverPublicGargAPI baseUrl =
  Named.GargPublicAPI
    { publicHomeAPI = api_home baseUrl
    , publicNodeAPI = Named.NodeAPI api_node
    }

api_home :: IsGargServer env err m => Text -> Named.HomeAPI (AsServerT m)
api_home baseUrl = Named.HomeAPI $ catMaybes
   <$> map (toPublicData baseUrl)
   <$> filterPublicDatas
   <$> selectPublic

api_node :: IsGargServer env err m => NodeId -> Named.FileAPI (AsServerT m)
api_node nId = Named.FileAPI $ do
  pubNodes <- publicNodes
  -- TODO optimize with SQL
  case Set.member nId pubNodes of
    False -> serverError $ err405 { errBody = "Not allowed" }
    True  -> fileApi nId

-------------------------------------------------------------------------


selectPublic :: HasNodeError err
             => DBCmd err [( Node HyperdataFolder, Maybe Int)]
selectPublic = selectPublicNodes

  -- For tests only
  -- pure $ replicate 6 defaultPublicData

filterPublicDatas :: [(Node HyperdataFolder, Maybe Int)]
                  -> [(Node HyperdataFolder, [NodeId])]
filterPublicDatas datas =
  map (\(n,mi) ->
          let mi' = UnsafeMkNodeId <$> mi in
                  ( _node_id n, (n, maybe [] (:[]) mi' ))
      ) datas
      & Map.fromListWith (\(n1,i1) (_n2,i2) -> (n1, i1 <> i2))
      & Map.filter (not . null . snd)
      & Map.elems

publicNodes :: HasNodeError err
            => Cmd err (Set NodeId)
publicNodes = do
  candidates <- filterPublicDatas <$> selectPublicNodes
  pure $ Set.fromList
       $ List.concat
       $ map (\(n, ns) -> (_node_id n) : ns) candidates


-- http://localhost:8008/api/v1.0/node/23543/file/download<Paste>
-- http://localhost:8000/images/Gargantextuel-212x300.jpg
toPublicData :: Text -> (Node HyperdataFolder, [NodeId]) -> Maybe PublicData
toPublicData base (n , mn) = do
  title <- (hd ^? (_Just . hf_data . cf_title))
  abstract <- (hd ^? (_Just . hf_data . cf_desc ))
  img <- (Just $ url' mn) -- "images/Gargantextuel-212x300.jpg"
  url <- (Just $ url' mn)
  date <- Just (show $ utc2year (n^.node_date))
  database <- (hd ^? (_Just . hf_data . cf_query))
  author <- (hd ^? (_Just . hf_data . cf_authors))
  pure $ PublicData { .. }
  where
    hd = head
       $ filter (\(HyperdataField cd _ _) -> cd == JSON)
       $ n^. (node_hyperdata . hc_fields)
    url' :: [NodeId] -> Text
    url' mn' = base
           <>   "/public/"
           <> (show $ (maybe 0 unNodeId $ head mn'))
           <> "/file/download"
