
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeApplications #-}

module Gargantext.API.Routes.Named (
  -- * Routes types

    API(..)
  , NamedAPI(..)
  , SwaggerAPI(..)
  , BackEndAPI(..)
  , MkBackEndAPI(..)
  , GargAPIVersion(..)
  , GargAPI'(..)
  , AuthAPI(..)
  , ForgotPasswordAPI(..)
  , ForgotPasswordAsyncAPI(..)
  , GargVersion(..)
  ) where

import Data.Text (Text)
import GHC.Generics
import Gargantext.API.Admin.Auth.Types
import Gargantext.API.Admin.FrontEnd (FrontEndAPI)
import Gargantext.API.Admin.Orchestrator.Types
import Gargantext.API.GraphQL
import Gargantext.API.Routes.Named.Private
import Gargantext.API.Routes.Named.Public
import Gargantext.API.Routes.Types
import Gargantext.Core.AsyncUpdates.Dispatcher.WebSocket qualified as Dispatcher
import Servant.API ((:>), (:-), JSON, ReqBody, Post, Get, QueryParam)
import Servant.API.Description (Summary)
import Servant.API.NamedRoutes
import Servant.Auth.Swagger ()
import Servant.Swagger.UI


newtype API mode = API
  { apiWithCustomErrorScheme :: mode :- WithCustomErrorScheme (NamedRoutes NamedAPI)
  } deriving Generic

data NamedAPI mode = NamedAPI
  { swaggerAPI  :: mode :- SwaggerSchemaUI "swagger-ui" "swagger.json"
  , backendAPI  :: mode :- NamedRoutes BackEndAPI
  , graphqlAPI  :: mode :- NamedRoutes GraphQLAPI
  , wsAPI       :: mode :- NamedRoutes Dispatcher.WSAPI
  -- NOTE: FrontEndAPI is Raw and is a catch-all so needs to be at the end!
  , frontendAPI :: mode :- FrontEndAPI
  } deriving Generic


newtype SwaggerAPI mode = SwaggerAPI
  { swaggerSchemaEp :: mode :- SwaggerSchemaUI "swagger-ui" "swagger.json"
  } deriving Generic


newtype BackEndAPI mode = BackEndAPI {
   backendAPI' :: mode :- NamedRoutes (MkBackEndAPI (GargAPIVersion GargAPI'))
  } deriving Generic


newtype MkBackEndAPI sub mode = MkBackEndAPI
  { mkBackEndAPI :: mode :- "api" :> Summary "Backend API " :> NamedRoutes sub
  } deriving Generic


newtype GargAPIVersion sub mode = GargAPIVersion
  { gargAPIVersion :: mode :- "v1.0" :> Summary "Garg API Version " :> NamedRoutes sub
  } deriving Generic


data GargAPI' mode = GargAPI'
  { gargAuthAPI                :: mode :- NamedRoutes AuthAPI
  , gargForgotPasswordAPI      :: mode :- "forgot-password" :> NamedRoutes ForgotPasswordAPI
  , gargForgotPasswordAsyncAPI :: mode :- "async" :> "forgot-password" :> NamedRoutes ForgotPasswordAsyncAPI
  , gargVersionAPI             :: mode :- NamedRoutes GargVersion
  , gargPrivateAPI             :: mode :- NamedRoutes GargPrivateAPI
  , gargPublicAPI              :: mode :- "public" :> NamedRoutes GargPublicAPI
  } deriving Generic


newtype AuthAPI mode = AuthAPI
  { authEp :: mode :- "auth"  :> Summary "AUTH API"
                              :> ReqBody '[JSON] AuthRequest
                              :> Post    '[JSON] AuthResponse
  } deriving Generic


data ForgotPasswordAPI mode = ForgotPasswordAPI
  { forgotPasswordPostEp :: mode :- Summary "Forgot password POST API"
                                 :> ReqBody '[JSON] ForgotPasswordRequest
                                 :> Post '[JSON] ForgotPasswordResponse
  , forgotPasswordGetEp  :: mode :- Summary "Forgot password GET API"
                                 :> QueryParam "uuid" Text
                                 :> Get '[JSON] ForgotPasswordGet
  } deriving Generic


data ForgotPasswordAsyncAPI mode = ForgotPasswordAsyncAPI
  { forgotPasswordAsyncEp :: mode :- Summary "Forgot password asnc"
                                  :> NamedRoutes (AsyncJobs JobLog '[JSON] ForgotPasswordAsyncParams JobLog)
  } deriving Generic


data GargVersion mode = GargVersion
  { gargVersionEp :: mode :- "version" :> Summary "Backend version" :> Get '[JSON] Text
  } deriving Generic
