{-# LANGUAGE InstanceSigs    #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ViewPatterns #-}


module Test.API.Routes where

import Data.Text.Encoding qualified as TE
import Fmt (Builder, (+|), (|+))
import Gargantext.API.Admin.Auth.Types (AuthRequest, AuthResponse, Token)
import Gargantext.API.Admin.Orchestrator.Types (JobLog, asyncJobsAPI')
import Gargantext.API.Errors
import Gargantext.API.HashedResponse (HashedResponse)
import Gargantext.API.Ngrams.Types ( NgramsTable, NgramsTablePatch, OrderBy, TabType, Versioned, VersionedWithCount )
import Gargantext.API.Routes.Named
import Gargantext.API.Routes.Named.Node
import Gargantext.API.Routes.Named.Private hiding (tableNgramsAPI)
import Gargantext.API.Routes.Named.Table
import Gargantext.API.Types () -- MimeUnrender instances
import Gargantext.Core.Text.Corpus.Query (RawQuery)
import Gargantext.Core.Types (ListId, NodeId, NodeType, NodeTableResult)
import Gargantext.Core.Types.Main (ListType)
import Gargantext.Core.Types.Query (Limit, MaxSize, MinSize, Offset)
import Gargantext.Database.Admin.Types.Hyperdata
import Gargantext.Database.Query.Facet qualified as Facet
import Gargantext.Prelude
import Network.HTTP.Types qualified as H
import Network.Wai.Handler.Warp (Port)
import Servant ((:<|>)(..))
import Servant.API.WebSocket qualified as WS
import Servant.Auth.Client qualified as S
import Servant.Client (ClientM)
import Servant.Client.Core (RunClient, HasClient(..), Request)
import Servant.Client.Generic ( genericClient, AsClientT )
import Servant.Job.Async


instance RunClient m => HasClient m WS.WebSocketPending where
  type Client m WS.WebSocketPending = H.Method ->  m ()

  clientWithRoute :: Proxy m -> Proxy WS.WebSocketPending -> Request -> Client m WS.WebSocketPending
  clientWithRoute _pm Proxy _req _httpMethod = do
    panicTrace "[WebSocket client] this is not implemented!"
    return ()

  hoistClientMonad _ _ f cl = \meth -> f (cl meth)

    
-- This is for requests made by http.client directly to hand-crafted URLs    
curApi :: Builder
curApi = "v1.0"

mkUrl :: Port -> Builder -> ByteString
mkUrl _port urlPiece =
  "/api/" +| curApi |+ urlPiece

gqlUrl :: ByteString
gqlUrl = "/gql"


-- | The client for the full API. It also serves as a \"proof\" that our
-- whole API has all the required instances to be used in a client.
clientRoutes :: API (AsClientT ClientM)
clientRoutes = genericClient

-- This is for Servant.Client requests
auth_api :: AuthRequest -> ClientM AuthResponse
auth_api = clientRoutes & apiWithCustomErrorScheme
                        & ($ GES_new)
                        & backendAPI
                        & backendAPI'
                        & mkBackEndAPI
                        & gargAPIVersion
                        & gargAuthAPI
                        & authEp

toServantToken :: Token -> S.Token
toServantToken = S.Token . TE.encodeUtf8

update_node :: Token
            -> NodeId
            -> UpdateNodeParams
            -> ClientM (JobStatus 'Safe JobLog)
update_node (toServantToken -> token) nodeId params =
  clientRoutes & apiWithCustomErrorScheme
               & ($ GES_new)
               & backendAPI
               & backendAPI'
               & mkBackEndAPI
               & gargAPIVersion
               & gargPrivateAPI
               & mkPrivateAPI
               & ($ token)
               & nodeEp
               & nodeEndpointAPI
               & ($ nodeId)
               & updateAPI
               & updateNodeEp
               & asyncJobsAPI'
               & (\(_ :<|> submitForm :<|> _) -> submitForm (JobInput params Nothing))

get_table_ngrams :: Token
                 -> NodeId
                 -> TabType
                 -> ListId
                 -> Limit
                 -> Maybe Offset
                 -> Maybe ListType
                 -> Maybe MinSize
                 -> Maybe MaxSize
                 -> Maybe OrderBy
                 -> Maybe Text
                 -> ClientM (VersionedWithCount NgramsTable)
get_table_ngrams (toServantToken -> token) nodeId =
  clientRoutes & apiWithCustomErrorScheme
               & ($ GES_new)
               & backendAPI
               & backendAPI'
               & mkBackEndAPI
               & gargAPIVersion
               & gargPrivateAPI
               & mkPrivateAPI
               & ($ token)
               & nodeEp
               & nodeEndpointAPI
               & ($ nodeId)
               & tableNgramsAPI
               & tableNgramsGetAPI
               & getNgramsTableEp

put_table_ngrams :: Token
                 -> NodeId
                 -> TabType
                 -> ListId
                 -> Versioned NgramsTablePatch
                 -> ClientM (Versioned NgramsTablePatch)
put_table_ngrams (toServantToken -> token) nodeId =
  clientRoutes & apiWithCustomErrorScheme
               & ($ GES_new)
               & backendAPI
               & backendAPI'
               & mkBackEndAPI
               & gargAPIVersion
               & gargPrivateAPI
               & mkPrivateAPI
               & ($ token)
               & nodeEp
               & nodeEndpointAPI
               & ($ nodeId)
               & tableNgramsAPI
               & tableNgramsPutAPI
               & putNgramsTableEp

get_table :: Token
          -> NodeId
          -> Maybe TabType
          -> Maybe Limit
          -> Maybe Offset
          -> Maybe Facet.OrderBy
          -> Maybe RawQuery
          -> Maybe Text
          -> ClientM (HashedResponse FacetTableResult)
get_table (toServantToken -> token) nodeId =
  clientRoutes & apiWithCustomErrorScheme
               & ($ GES_new)
               & backendAPI
               & backendAPI'
               & mkBackEndAPI
               & gargAPIVersion
               & gargPrivateAPI
               & mkPrivateAPI
               & ($ token)
               & nodeEp
               & nodeEndpointAPI
               & ($ nodeId)
               & tableAPI
               & getTableEp

get_children :: Token
             -> NodeId
             -> Maybe NodeType
             -> Maybe Offset
             -> Maybe Limit
             -> ClientM (NodeTableResult HyperdataAny)
get_children (toServantToken -> token) nodeId =
  clientRoutes & apiWithCustomErrorScheme
               & ($ GES_new)
               & backendAPI
               & backendAPI'
               & mkBackEndAPI
               & gargAPIVersion
               & gargPrivateAPI
               & mkPrivateAPI
               & ($ token)
               & nodeEp
               & nodeEndpointAPI
               & ($ nodeId)
               & childrenAPI
               & summaryChildrenEp

