{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE NamedFieldPuns    #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell   #-}
module Data.Morpheus.Execution.Document.Encode
  ( deriveEncode
  ) where
import           Data.Text                               (unpack)
import           Data.Typeable                           (Typeable)
import           Language.Haskell.TH
import           Data.Morpheus.Execution.Server.Encode   (Encode (..), ObjectResolvers (..))
import           Data.Morpheus.Types.GQLType             (TRUE)
import           Data.Morpheus.Types.Internal.Data       (DataField (..), isSubscription)
import           Data.Morpheus.Types.Internal.DataD      (ConsD (..), GQLTypeD (..), TypeD (..))
import           Data.Morpheus.Types.Internal.TH         (applyT, instanceHeadMultiT, typeT)
import           Data.Morpheus.Types.Internal.Validation (ResolveT)
import           Data.Morpheus.Types.Internal.Value      (Value)
import           Data.Morpheus.Types.Resolver
deriveEncode :: GQLTypeD -> Q [Dec]
deriveEncode GQLTypeD {typeKindD, typeD = TypeD {tName, tCons = [ConsD {cFields}]}} =
  pure <$> instanceD (cxt constrains) appHead methods
  where
    result = appT resultMonad (conT ''Value)
      where
        resultMonad
          | isSubscription typeKindD = typeT ''SubResolveT ["m", "e", "c"] 
          | otherwise = typeT ''ResolveT ["m"] 
    mainType = applyT (mkName tName) [mainTypeArg] 
      where
        mainTypeArg
          | isSubscription typeKindD = typeT ''SubResolver ["m", "e", "c"] 
          | otherwise = typeT ''Resolver ["m"] 
    
    
    constrains = [typeT ''Monad ["m"], typeT ''Typeable ["m"]]
    
    
    appHead = instanceHeadMultiT ''ObjectResolvers (conT ''TRUE) [mainType, result]
    
    
    methods = [funD 'objectResolvers [clause argsE (normalB body) []]]
      where
        argsE = [varP (mkName "_"), conP (mkName tName) (map (varP . mkName) varNames)]
        body = listE $ map decodeVar varNames
        decodeVar name = [|(name, encode $(varName))|]
          where
            varName = varE $ mkName name
        varNames = map (unpack . fieldName) cFields
deriveEncode _ = pure []