-- | Specification for an API endpoint as a composition of Request and Response components
-- at the Type level.
module Hreq.Core.API.Internal where

import Data.Kind (Type)
import Data.Singletons
import GHC.TypeLits

import Hreq.Core.API.Request
import Hreq.Core.API.Response

-- * API type
data Api a =
    Req [ ReqContent a]
  | Res [ ResContent a ]

-- * API GADT as a singleton.
data SApi (a :: Api Type)
  = forall b . a ~ 'Req b => SReq (Sing b)
  | forall b . a ~ 'Res b => SRes (Sing b)
type instance Sing = SApi

-- * SingI instance for API types
instance (SingI content) => SingI ('Res content :: Api Type) where
  sing = SRes sing

instance (SingI content) => SingI ('Req content :: Api Type) where
  sing = SReq sing

-- * API Type combinators
-- Used in concatenation of API types.
--
-- Examples
--
-- >>> PathQueryWithEmptyResponse = "hello" :> QueryFlag "young" :> Get '[]
-- >>> PathQueryWithResponse = "hello" :> QueryFlag "young" :> Get '[ ResBody JSON String, ResHeader [ "headerName" := String ]]
-- >>> JsonBodyAndResponse = "hello" :> JsonBody User :> GetJson User

infixr 7 :>

data (a :: k1) :> (b :: k2)

-- | For representing type level tuples where first value is a Symbol
infixr 1 :=

type (a :: Symbol) := (b :: k2) = '( a, b)

-- $setup
-- >>> import Hreq.Core.API
-- >>> import GHC.Generics
-- >>> import Data.Aeson
-- >>> data User = User deriving (Show)
-- >>> instance ToJSON User where toJSON = undefined
-- >>> instance FromJSON User where parseJSON = undefined