{-|
Module: BattlePlace.WebApi
Description: Web API definitions.
License: MIT
-}

{-# LANGUAGE DataKinds, DeriveGeneric, GeneralizedNewtypeDeriving, TypeOperators #-}

module BattlePlace.WebApi
        ( WebApi
        , ClientAuthRequest(..)
        , ClientAuthResponse(..)
        , MatchRequest(..)
        , MatchResponse(..)
        , MatchStatusResponse(..)
        , SessionResultRequest(..)
        , ServerMatchRequest(..)
        , ServerMatchResponse(..)
        , ServerMatchCancelRequest(..)
        , ServerMatchCancelResponse(..)
        , ServerMatchSessionsRequest(..)
        , ServerMatchSessionsResponse(..)
        , ServerSessionResultRequest(..)
        ) where

import qualified Data.Aeson as J
import qualified Data.Text as T
import qualified Data.Vector as V
import qualified Data.Vector.Unboxed as VU
import GHC.Generics(Generic)
import Servant.API

import BattlePlace.Token.Types
import BattlePlace.Util
import BattlePlace.WebApi.Auth
import BattlePlace.WebApi.Types

type WebApi = "v1a" :>
        (    "client" :>
                (    "auth" :> ReqBody '[JSON] ClientAuthRequest :> Post '[JSON] ClientAuthResponse
                :<|> "match" :>
                        (    AuthProtect ClientToken :> ReqBody '[JSON] MatchRequest :> Post '[JSON] MatchResponse
                        :<|> AuthProtect ClientToken :> Capture "matchToken" (InternalToken MatchToken) :> Get '[JSON] MatchStatusResponse
                        :<|> AuthProtect ClientToken :> Capture "matchToken" (InternalToken MatchToken) :> Delete '[JSON] ()
                        )
                :<|> "session" :> Capture "sessionToken" (InternalToken SessionToken) :>
                        (    "result" :> AuthProtect ClientToken :> ReqBody '[JSON] SessionResultRequest :> Post '[JSON] ()
                        )
                :<|> "info" :>
                        (    "stats" :> AuthProtect ClientToken :> Get '[JSON] UserStats
                        )
                )
        :<|> "server" :>
                (    "match" :>
                        (    ReqBody '[JSON] ServerMatchRequest :> Post '[JSON] ServerMatchResponse
                        :<|> ReqBody '[JSON] ServerMatchCancelRequest :> Delete '[JSON] ServerMatchCancelResponse
                        :<|> "sessions" :> ReqBody '[JSON] ServerMatchSessionsRequest :> Post '[JSON] ServerMatchSessionsResponse
                        )
                :<|> "session" :> Capture "serverSessionToken" (InternalToken ServerSessionToken) :>
                        (    "result" :> ReqBody '[JSON] ServerSessionResultRequest :> Post '[JSON] ()
                        )
                )
        )

data ClientAuthRequest = ClientAuthRequest
        { clientAuthRequest_projectId :: {-# UNPACK #-} !ProjectId
        , clientAuthRequest_auth :: !Auth
        } deriving Generic
instance J.FromJSON ClientAuthRequest where
        parseJSON = J.genericParseJSON jsonOptions
instance J.ToJSON ClientAuthRequest where
        toJSON = J.genericToJSON jsonOptions
        toEncoding = J.genericToEncoding jsonOptions

data ClientAuthResponse
        = ClientAuthResponse_authenticated
                { clientAuthResponse_clientToken :: !(InternalToken ClientToken)
                , clientAuthResponse_name :: !T.Text
                , clientAuthResponse_pictureUrl :: !T.Text
                }
        | ClientAuthResponse_notAuthenticated
                { clientAuthResponse_error :: !T.Text
                }
        deriving Generic
instance J.FromJSON ClientAuthResponse where
        parseJSON = J.genericParseJSON jsonOptions
instance J.ToJSON ClientAuthResponse where
        toJSON = J.genericToJSON jsonOptions
        toEncoding = J.genericToEncoding jsonOptions

data MatchRequest = MatchRequest
        { matchRequest_teamSizes :: !(VU.Vector MatchTeamSize)
        , matchRequest_maxMatchTime :: {-# UNPACK #-} !Int
        , matchRequest_matchTag :: !(Maybe MatchTag)
        , matchRequest_serverTag :: !(Maybe ServerTag)
        , matchRequest_info :: !(Maybe MatchPlayerInfo)
        } deriving Generic
instance J.FromJSON MatchRequest where
        parseJSON = J.genericParseJSON jsonOptions
instance J.ToJSON MatchRequest where
        toJSON = J.genericToJSON jsonOptions
        toEncoding = J.genericToEncoding jsonOptions

data MatchResponse = MatchResponse
        { matchResponse_matchToken :: !(InternalToken MatchToken)
        } deriving Generic
instance J.FromJSON MatchResponse where
        parseJSON = J.genericParseJSON jsonOptions
instance J.ToJSON MatchResponse where
        toJSON = J.genericToJSON jsonOptions
        toEncoding = J.genericToEncoding jsonOptions

data MatchStatusResponse
        = MatchStatusResponse_notFound
        | MatchStatusResponse_inProgress
        | MatchStatusResponse_matched
                { matchStatusResponse_session :: !MatchSession
                }
        | MatchStatusResponse_failed
                { matchStatusResponse_reason :: !MatchFailureReason
                }
        deriving Generic
instance J.FromJSON MatchStatusResponse where
        parseJSON = J.genericParseJSON jsonOptions
instance J.ToJSON MatchStatusResponse where
        toJSON = J.genericToJSON jsonOptions
        toEncoding = J.genericToEncoding jsonOptions

data SessionResultRequest
        = SessionResultRequest_finished
                { sessionResultRequest_ranks :: !(V.Vector Int)
                }
        | SessionResultRequest_cancelled
        deriving Generic
instance J.FromJSON SessionResultRequest where
        parseJSON = J.genericParseJSON jsonOptions
instance J.ToJSON SessionResultRequest where
        toJSON = J.genericToJSON jsonOptions
        toEncoding = J.genericToEncoding jsonOptions

data ClientDataRequest = ClientDataRequest
        { clientDataRequest_after :: !(Maybe T.Text)
        } deriving Generic
instance J.FromJSON ClientDataRequest where
        parseJSON = J.genericParseJSON jsonOptions
instance J.ToJSON ClientDataRequest where
        toJSON = J.genericToJSON jsonOptions
        toEncoding = J.genericToEncoding jsonOptions

data ServerMatchRequest = ServerMatchRequest
        { serverMatchRequest_projectId :: {-# UNPACK #-} !ProjectId
        , serverMatchRequest_projectServerToken :: !ProjectServerToken
        , serverMatchRequest_serverTag :: !(Maybe ServerTag)
        , serverMatchRequest_name :: !ProjectServerName
        , serverMatchRequest_info :: !(Maybe MatchServerInfo)
        , serverMatchRequest_timeout :: !(Maybe Int)
        } deriving Generic
instance J.FromJSON ServerMatchRequest where
        parseJSON = J.genericParseJSON jsonOptions
instance J.ToJSON ServerMatchRequest where
        toJSON = J.genericToJSON jsonOptions
        toEncoding = J.genericToEncoding jsonOptions

data ServerMatchResponse
        = ServerMatchResponse_registered
        | ServerMatchResponse_unused
        deriving Generic
instance J.FromJSON ServerMatchResponse where
        parseJSON = J.genericParseJSON jsonOptions
instance J.ToJSON ServerMatchResponse where
        toJSON = J.genericToJSON jsonOptions
        toEncoding = J.genericToEncoding jsonOptions

data ServerMatchCancelRequest = ServerMatchCancelRequest
        { serverMatchCancelRequest_projectId :: {-# UNPACK #-} !ProjectId
        , serverMatchCancelRequest_projectServerToken :: !ProjectServerToken
        , serverMatchCancelRequest_name :: !ProjectServerName
        } deriving Generic
instance J.FromJSON ServerMatchCancelRequest where
        parseJSON = J.genericParseJSON jsonOptions
instance J.ToJSON ServerMatchCancelRequest where
        toJSON = J.genericToJSON jsonOptions
        toEncoding = J.genericToEncoding jsonOptions

data ServerMatchCancelResponse
        = ServerMatchCancelResponse_cancelled
        | ServerMatchCancelResponse_unused
        deriving Generic
instance J.FromJSON ServerMatchCancelResponse where
        parseJSON = J.genericParseJSON jsonOptions
instance J.ToJSON ServerMatchCancelResponse where
        toJSON = J.genericToJSON jsonOptions
        toEncoding = J.genericToEncoding jsonOptions

data ServerMatchSessionsRequest = ServerMatchSessionsRequest
        { serverMatchSessionsRequest_projectId :: {-# UNPACK #-} !ProjectId
        , serverMatchSessionsRequest_projectServerToken :: !ProjectServerToken
        , serverMatchSessionsRequest_name :: !ProjectServerName
        } deriving Generic
instance J.FromJSON ServerMatchSessionsRequest where
        parseJSON = J.genericParseJSON jsonOptions
instance J.ToJSON ServerMatchSessionsRequest where
        toJSON = J.genericToJSON jsonOptions
        toEncoding = J.genericToEncoding jsonOptions

data ServerMatchSessionsResponse = ServerMatchSessionsResponse
        { serverMatchSessionsResponse_sessions :: !(V.Vector MatchServerSession)
        } deriving Generic
instance J.FromJSON ServerMatchSessionsResponse where
        parseJSON = J.genericParseJSON jsonOptions
instance J.ToJSON ServerMatchSessionsResponse where
        toJSON = J.genericToJSON jsonOptions
        toEncoding = J.genericToEncoding jsonOptions

data ServerSessionResultRequest
        = ServerSessionResultRequest_finished
                { serverSessionResultRequest_ranks :: !(V.Vector Int)
                }
        | ServerSessionResultRequest_cancelled
        deriving Generic
instance J.FromJSON ServerSessionResultRequest where
        parseJSON = J.genericParseJSON jsonOptions
instance J.ToJSON ServerSessionResultRequest where
        toJSON = J.genericToJSON jsonOptions
        toEncoding = J.genericToEncoding jsonOptions