{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskellQuotes #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Data.Morpheus.CodeGen.Server.Internal.AST
  ( ModuleDefinition (..),
    CodeGenConfig (..),
    ServerDeclaration (..),
    GQLTypeDefinition (..),
    CONST,
    TypeKind (..),
    TypeName,
    TypeRef (..),
    TypeWrapper (..),
    unpackName,
    DerivingClass (..),
    FIELD_TYPE_WRAPPER (..),
    Kind (..),
    ServerDirectiveUsage (..),
    TypeValue (..),
    InterfaceDefinition (..),
    GQLDirectiveTypeClass (..),
  )
where

import Data.Morpheus.CodeGen.Internal.AST
  ( CodeGenType,
    CodeGenTypeName,
    DerivingClass (..),
    FIELD_TYPE_WRAPPER (..),
    TypeValue (..),
  )
import Data.Morpheus.CodeGen.TH
  ( PrintExp (..),
    PrintType (..),
  )
import Data.Morpheus.Server.Types
  ( SCALAR,
    TYPE,
    enumDirective,
    fieldDirective,
    typeDirective,
  )
import Data.Morpheus.Types.Internal.AST
  ( CONST,
    DirectiveLocation (..),
    FieldName,
    TypeKind (..),
    TypeName,
    TypeRef (..),
    TypeWrapper (..),
    Value,
    unpackName,
  )
import Language.Haskell.TH.Lib (appE, conT, varE)
import Prettyprinter (Pretty (..), (<+>))
import Relude

data ModuleDefinition = ModuleDefinition
  { ModuleDefinition -> Text
moduleName :: Text,
    ModuleDefinition -> [(Text, [Text])]
imports :: [(Text, [Text])],
    ModuleDefinition -> [Text]
extensions :: [Text],
    ModuleDefinition -> [ServerDeclaration]
types :: [ServerDeclaration]
  }

data Kind
  = Scalar
  | Type
  deriving (Int -> Kind -> ShowS
[Kind] -> ShowS
Kind -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Kind] -> ShowS
$cshowList :: [Kind] -> ShowS
show :: Kind -> String
$cshow :: Kind -> String
showsPrec :: Int -> Kind -> ShowS
$cshowsPrec :: Int -> Kind -> ShowS
Show, Kind -> Kind -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Kind -> Kind -> Bool
$c/= :: Kind -> Kind -> Bool
== :: Kind -> Kind -> Bool
$c== :: Kind -> Kind -> Bool
Eq)

instance Pretty Kind where
  pretty :: forall ann. Kind -> Doc ann
pretty Kind
Type = Doc ann
"TYPE"
  pretty Kind
Scalar = Doc ann
"SCALAR"

instance PrintType Kind where
  printType :: Kind -> TypeQ
printType Kind
Scalar = forall (m :: * -> *). Quote m => Name -> m Type
conT ''SCALAR
  printType Kind
Type = forall (m :: * -> *). Quote m => Name -> m Type
conT ''TYPE

data ServerDirectiveUsage
  = TypeDirectiveUsage TypeValue
  | FieldDirectiveUsage FieldName TypeValue
  | EnumDirectiveUsage TypeName TypeValue
  deriving (Int -> ServerDirectiveUsage -> ShowS
[ServerDirectiveUsage] -> ShowS
ServerDirectiveUsage -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ServerDirectiveUsage] -> ShowS
$cshowList :: [ServerDirectiveUsage] -> ShowS
show :: ServerDirectiveUsage -> String
$cshow :: ServerDirectiveUsage -> String
showsPrec :: Int -> ServerDirectiveUsage -> ShowS
$cshowsPrec :: Int -> ServerDirectiveUsage -> ShowS
Show)

instance PrintExp ServerDirectiveUsage where
  printExp :: ServerDirectiveUsage -> ExpQ
printExp (TypeDirectiveUsage TypeValue
x) = forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
appE (forall (m :: * -> *). Quote m => Name -> m Exp
varE 'typeDirective) (forall a. PrintExp a => a -> ExpQ
printExp TypeValue
x)
  printExp (FieldDirectiveUsage FieldName
field TypeValue
x) = forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
appE (forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
appE (forall (m :: * -> *). Quote m => Name -> m Exp
varE 'fieldDirective) [|field|]) (forall a. PrintExp a => a -> ExpQ
printExp TypeValue
x)
  printExp (EnumDirectiveUsage TypeName
enum TypeValue
x) = forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
appE (forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
appE (forall (m :: * -> *). Quote m => Name -> m Exp
varE 'enumDirective) [|enum|]) (forall a. PrintExp a => a -> ExpQ
printExp TypeValue
x)

instance Pretty ServerDirectiveUsage where
  pretty :: forall ann. ServerDirectiveUsage -> Doc ann
pretty (TypeDirectiveUsage TypeValue
value) = Doc ann
"typeDirective" forall ann. Doc ann -> Doc ann -> Doc ann
<+> forall a ann. Pretty a => a -> Doc ann
pretty TypeValue
value
  pretty (FieldDirectiveUsage FieldName
place TypeValue
value) = Doc ann
"fieldDirective" forall ann. Doc ann -> Doc ann -> Doc ann
<+> forall a ann. Pretty a => a -> Doc ann
pretty (forall b a. (Show a, IsString b) => a -> b
show FieldName
place :: String) forall ann. Doc ann -> Doc ann -> Doc ann
<+> forall a ann. Pretty a => a -> Doc ann
pretty TypeValue
value
  pretty (EnumDirectiveUsage TypeName
place TypeValue
value) = Doc ann
"enumDirective" forall ann. Doc ann -> Doc ann -> Doc ann
<+> forall a ann. Pretty a => a -> Doc ann
pretty (forall b a. (Show a, IsString b) => a -> b
show TypeName
place :: String) forall ann. Doc ann -> Doc ann -> Doc ann
<+> forall a ann. Pretty a => a -> Doc ann
pretty TypeValue
value

data GQLTypeDefinition = GQLTypeDefinition
  { GQLTypeDefinition -> CodeGenTypeName
gqlTarget :: CodeGenTypeName,
    GQLTypeDefinition -> Kind
gqlKind :: Kind,
    GQLTypeDefinition -> [ServerDirectiveUsage]
gqlTypeDirectiveUses :: [ServerDirectiveUsage],
    GQLTypeDefinition -> Map Text (Value CONST)
gqlTypeDefaultValues :: Map Text (Value CONST),
    GQLTypeDefinition -> Maybe (TypeKind, Text)
dropNamespace :: Maybe (TypeKind, Text)
  }
  deriving (Int -> GQLTypeDefinition -> ShowS
[GQLTypeDefinition] -> ShowS
GQLTypeDefinition -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [GQLTypeDefinition] -> ShowS
$cshowList :: [GQLTypeDefinition] -> ShowS
show :: GQLTypeDefinition -> String
$cshow :: GQLTypeDefinition -> String
showsPrec :: Int -> GQLTypeDefinition -> ShowS
$cshowsPrec :: Int -> GQLTypeDefinition -> ShowS
Show)

data InterfaceDefinition = InterfaceDefinition
  { InterfaceDefinition -> TypeName
aliasName :: TypeName,
    InterfaceDefinition -> TypeName
interfaceName :: TypeName,
    InterfaceDefinition -> TypeName
unionName :: TypeName
  }
  deriving (Int -> InterfaceDefinition -> ShowS
[InterfaceDefinition] -> ShowS
InterfaceDefinition -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [InterfaceDefinition] -> ShowS
$cshowList :: [InterfaceDefinition] -> ShowS
show :: InterfaceDefinition -> String
$cshow :: InterfaceDefinition -> String
showsPrec :: Int -> InterfaceDefinition -> ShowS
$cshowsPrec :: Int -> InterfaceDefinition -> ShowS
Show)

data GQLDirectiveTypeClass = GQLDirectiveTypeClass
  { GQLDirectiveTypeClass -> CodeGenTypeName
directiveTypeName :: CodeGenTypeName,
    GQLDirectiveTypeClass -> [DirectiveLocation]
directiveLocations :: [DirectiveLocation]
  }
  deriving (Int -> GQLDirectiveTypeClass -> ShowS
[GQLDirectiveTypeClass] -> ShowS
GQLDirectiveTypeClass -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [GQLDirectiveTypeClass] -> ShowS
$cshowList :: [GQLDirectiveTypeClass] -> ShowS
show :: GQLDirectiveTypeClass -> String
$cshow :: GQLDirectiveTypeClass -> String
showsPrec :: Int -> GQLDirectiveTypeClass -> ShowS
$cshowsPrec :: Int -> GQLDirectiveTypeClass -> ShowS
Show)

data ServerDeclaration
  = GQLTypeInstance GQLTypeDefinition
  | GQLDirectiveInstance GQLDirectiveTypeClass
  | DataType CodeGenType
  | ScalarType {ServerDeclaration -> Text
scalarTypeName :: Text}
  | InterfaceType InterfaceDefinition
  deriving (Int -> ServerDeclaration -> ShowS
[ServerDeclaration] -> ShowS
ServerDeclaration -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ServerDeclaration] -> ShowS
$cshowList :: [ServerDeclaration] -> ShowS
show :: ServerDeclaration -> String
$cshow :: ServerDeclaration -> String
showsPrec :: Int -> ServerDeclaration -> ShowS
$cshowsPrec :: Int -> ServerDeclaration -> ShowS
Show)

newtype CodeGenConfig = CodeGenConfig
  { CodeGenConfig -> Bool
namespace :: Bool
  }