{-# LANGUAGE StarIsType #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}

module Admin.Components.Internal.TypeLevel
  ( NamesOf
  , NameOf
  , ApisOf
  , ApiOf
  , ManySymbolVal(..)
  ) where

import Admin.Components.Component (Component(..))
import Data.Data (Proxy(..))
import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)
import Servant.API ((:<|>), (:>))

type family NameOf (x :: *) where
  NameOf (Component name api) = (name :: Symbol)

type family ApiOf (x :: *) where
  ApiOf (Component (name :: Symbol) api) = name :> api

type family NamesOf (xs :: [*]) where
  NamesOf '[] = '[]
  NamesOf (x ': xs) = NameOf x ': NamesOf xs

type family ApisOf (xs :: [*]) where
  ApisOf (x ': '[]) = ApiOf x
  ApisOf (x ': xs) = ApiOf x :<|> ApisOf xs

-- Type class ManySymbolVal
-- Source: https://stackoverflow.com/a/37365020
-- Author: Andrew Thaddeus Martin
class ManySymbolVal (xs :: [Symbol]) where
  manySymbolVal :: proxy xs -> [String]

instance ManySymbolVal '[] where
  manySymbolVal :: proxy '[] -> [String]
manySymbolVal proxy '[]
_ = []

instance (KnownSymbol a, ManySymbolVal as) => ManySymbolVal (a ': as) where
  manySymbolVal :: proxy (a : as) -> [String]
manySymbolVal proxy (a : as)
_ =
    Proxy a -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal (Proxy a
forall k (t :: k). Proxy t
Proxy :: Proxy a) String -> [String] -> [String]
forall a. a -> [a] -> [a]
: Proxy as -> [String]
forall (xs :: [Symbol]) (proxy :: [Symbol] -> *).
ManySymbolVal xs =>
proxy xs -> [String]
manySymbolVal (Proxy as
forall k (t :: k). Proxy t
Proxy :: Proxy as)