{-# OPTIONS_HADDOCK not-home #-}

{- |
Module      : Servant.API.Routes.Internal.Header
Copyright   : (c) Frederick Pringle, 2025
License     : BSD-3-Clause
Maintainer  : freddyjepringle@gmail.com

Internal module, subject to change.
-}
module Servant.API.Routes.Internal.Header
  ( HeaderRep (..)
  , mkHeaderRep
  , GetHeaderReps (..)
  )
where

import Data.Aeson
import Data.Kind (Type)
import Data.Text
import Data.Typeable
import GHC.TypeLits
import Servant.API
import "this" Servant.API.Routes.Utils

-- | Convenience function to construct a 'HeaderRep' from @sym :: 'Symbol'@ and @a :: Type'@.
mkHeaderRep ::
  forall sym a.
  (KnownSymbol sym, Typeable a) =>
  HeaderRep
mkHeaderRep :: forall (sym :: Symbol) a.
(KnownSymbol sym, Typeable a) =>
HeaderRep
mkHeaderRep =
  HeaderRep
    { _hName :: Text
_hName = forall (name :: Symbol). KnownSymbol name => Text
knownSymbolT @sym
    , _hType :: TypeRep
_hType = forall a. Typeable a => TypeRep
typeRepOf @a
    }

{- | Simple term-level representation of a 'Servant.API.Header.Header'.

A type-level @'Servant.API.Header.Header' (sym :: 'GHC.TypeLits.Symbol') typ@ should correspond to
@'HeaderRep' { _hName = str, _hType =  typRep }@, where @str@ is the term-level equivalent
of @sym@ and @typRep@ is the term-level representation of @typ@.
-}
data HeaderRep = HeaderRep
  { HeaderRep -> Text
_hName :: Text
  , HeaderRep -> TypeRep
_hType :: TypeRep
  }
  deriving (Int -> HeaderRep -> ShowS
[HeaderRep] -> ShowS
HeaderRep -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [HeaderRep] -> ShowS
$cshowList :: [HeaderRep] -> ShowS
show :: HeaderRep -> String
$cshow :: HeaderRep -> String
showsPrec :: Int -> HeaderRep -> ShowS
$cshowsPrec :: Int -> HeaderRep -> ShowS
Show, HeaderRep -> HeaderRep -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: HeaderRep -> HeaderRep -> Bool
$c/= :: HeaderRep -> HeaderRep -> Bool
== :: HeaderRep -> HeaderRep -> Bool
$c== :: HeaderRep -> HeaderRep -> Bool
Eq, Eq HeaderRep
HeaderRep -> HeaderRep -> Bool
HeaderRep -> HeaderRep -> Ordering
HeaderRep -> HeaderRep -> HeaderRep
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: HeaderRep -> HeaderRep -> HeaderRep
$cmin :: HeaderRep -> HeaderRep -> HeaderRep
max :: HeaderRep -> HeaderRep -> HeaderRep
$cmax :: HeaderRep -> HeaderRep -> HeaderRep
>= :: HeaderRep -> HeaderRep -> Bool
$c>= :: HeaderRep -> HeaderRep -> Bool
> :: HeaderRep -> HeaderRep -> Bool
$c> :: HeaderRep -> HeaderRep -> Bool
<= :: HeaderRep -> HeaderRep -> Bool
$c<= :: HeaderRep -> HeaderRep -> Bool
< :: HeaderRep -> HeaderRep -> Bool
$c< :: HeaderRep -> HeaderRep -> Bool
compare :: HeaderRep -> HeaderRep -> Ordering
$ccompare :: HeaderRep -> HeaderRep -> Ordering
Ord)

instance ToJSON HeaderRep where
  toJSON :: HeaderRep -> Value
toJSON HeaderRep {TypeRep
Text
_hType :: TypeRep
_hName :: Text
_hType :: HeaderRep -> TypeRep
_hName :: HeaderRep -> Text
..} =
    [Pair] -> Value
object
      [ Key
"name" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Text
_hName
      , Key
"type" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= TypeRep -> Value
typeRepToJSON TypeRep
_hType
      ]

{- | Utility class to let us get a value-level list of 'HeaderRep's from a
type-level list of 'Servant.API.Header.Header's. See the implementation of
@'Servant.API.Route.HasRoutes' ('Verb' method status ctypes ('Headers' hs a))@ for an example.
-}
class GetHeaderReps (hs :: [Type]) where
  getHeaderReps :: [HeaderRep]

instance GetHeaderReps '[] where
  getHeaderReps :: [HeaderRep]
getHeaderReps = []

instance
  (GetHeaderReps rest, KnownSymbol h, Typeable v) =>
  GetHeaderReps (Header h v ': rest)
  where
  getHeaderReps :: [HeaderRep]
getHeaderReps = HeaderRep
header forall a. a -> [a] -> [a]
: forall (hs :: [*]). GetHeaderReps hs => [HeaderRep]
getHeaderReps @rest
    where
      header :: HeaderRep
header = forall (sym :: Symbol) a.
(KnownSymbol sym, Typeable a) =>
HeaderRep
mkHeaderRep @h @v