
{-# LANGUAGE TypeOperators #-}

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

    API(..)
  , NamedAPI(..)
  , SwaggerAPI(..)
  , BackEndAPI(..)
  , MkBackEndAPI(..)
  , GargAPIVersion(..)
  , GargAPI'(..)
  , AuthAPI(..)
  , ForgotPasswordAPI(..)
  , ForgotPasswordAsyncAPI(..)
  , GargVersion(..)
  , module Gargantext.API.Routes.Named.Private
  ) where

import Data.Text (Text)
import GHC.Generics (Generic)
import Gargantext.API.Admin.Auth.Types
import Gargantext.API.Admin.FrontEnd (FrontEndAPI)
import Gargantext.API.GraphQL (GraphQLAPI)
import Gargantext.API.Routes.Named.Private (GargPrivateAPI)
import Gargantext.API.Routes.Named.Public (GargPublicAPI)
import Gargantext.API.Routes.Types (WithCustomErrorScheme)
import Gargantext.API.Worker (WorkerAPI)
import Gargantext.Core.Notifications.Dispatcher.WebSocket qualified as Dispatcher
import Servant.API ((:>), (:-), JSON, ReqBody, Post, Get, QueryParam)
import Servant.API.Description (Summary)
import Servant.API.NamedRoutes (NamedRoutes)
import Servant.Auth.Swagger ()  -- toSwagger instance
import Servant.Swagger.UI (SwaggerSchemaUI)


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 :- 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 (WorkerAPI '[JSON] ForgotPasswordAsyncParams)
  } deriving Generic


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