content: {-# LANGUAGE NoImplicitPrelude #-}
  
  module Data.Morpheus.Client.CodeGen.TH
    ( deriveIfNotDefined,
      declareIfNotDeclared,
    )
  where
  
  import Data.Morpheus.CodeGen.Internal.AST
    ( CodeGenType (..),
      CodeGenTypeName (..),
      TypeClassInstance (..),
      getFullName,
    )
  import Data.Morpheus.CodeGen.TH (toName)
  import Language.Haskell.TH
  import Relude
  
  isTypeDeclared :: CodeGenTypeName -> Q Bool
  isTypeDeclared name = isJust <$> lookupTypeName (toString $ getFullName name)
  
  isInstanceDefined :: Name -> CodeGenTypeName -> Q Bool
  isInstanceDefined typeClass tName = do
    exists <- isTypeDeclared tName
    if exists
      then isInstance typeClass [ConT (toName tName)]
      else pure False
  
  deriveIfNotDefined :: (TypeClassInstance a -> Q Dec) -> TypeClassInstance a -> Q [Dec]
  deriveIfNotDefined f dec = do
    exists <- isInstanceDefined (typeClassName dec) (typeClassTarget dec)
    traverse f [dec | not exists]
  
  declareIfNotDeclared :: (CodeGenType -> Q a) -> CodeGenType -> Q [a]
  declareIfNotDeclared f codeGenType = do
    exists <- isTypeDeclared (cgTypeName codeGenType)
    traverse f [codeGenType | not exists]
  