content: {-# LANGUAGE DeriveAnyClass #-}
  {-# LANGUAGE DeriveGeneric #-}
  {-# LANGUAGE DuplicateRecordFields #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE TypeFamilies #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  
  module Data.Morpheus.Client.Schema.JSON.Types
    ( Introspection (..),
      Schema (..),
      Type (..),
      Field (..),
      InputValue (..),
      EnumValue (..),
      JSONResponse (..),
    )
  where
  
  import Data.Aeson
  --
  -- MORPHEUS
  import Data.Morpheus.Client.Schema.JSON.TypeKind (TypeKind)
  import Data.Morpheus.Client.Schema.JSON.TypeRef (TypeRef)
  import Data.Morpheus.Types.Internal.AST
    ( FieldName,
      GQLError,
      TypeName,
    )
  import Relude hiding (Type)
  
  -- TYPES FOR DECODING JSON INTROSPECTION
  --
  newtype Introspection = Introspection
    { __schema :: Schema
    }
    deriving (Generic, Show, FromJSON)
  
  data Schema = Schema
    { types :: [Type],
      queryType :: TypeRef,
      mutationType :: Maybe TypeRef,
      subscriptionType :: Maybe TypeRef
    }
    deriving (Generic, Show, FromJSON)
  
  data Type = Type
    { kind :: TypeKind,
      name :: Maybe TypeName,
      fields :: Maybe [Field],
      interfaces :: Maybe [Type],
      possibleTypes :: Maybe [Type],
      enumValues :: Maybe [EnumValue],
      inputFields :: Maybe [InputValue],
      ofType :: Maybe Type
    }
    deriving (Generic, Show, FromJSON)
  
  -- FIELD
  data Field = Field
    { fieldName :: FieldName,
      fieldArgs :: [InputValue],
      fieldType :: Type
    }
    deriving (Show, Generic)
  
  instance FromJSON Field where
    parseJSON = withObject "Field" objectParser
      where
        objectParser o = Field <$> o .: "name" <*> o .: "args" <*> o .: "type"
  
  -- INPUT
  data InputValue = InputValue
    { inputName :: FieldName,
      inputType :: Type
    }
    deriving (Show, Generic)
  
  instance FromJSON InputValue where
    parseJSON = withObject "InputValue" objectParser
      where
        objectParser o = InputValue <$> o .: "name" <*> o .: "type"
  
  -- ENUM
  newtype EnumValue = EnumValue
    { enumName :: TypeName
    }
    deriving (Generic, Show)
  
  instance FromJSON EnumValue where
    parseJSON = withObject "EnumValue" objectParser
      where
        objectParser o = EnumValue <$> o .: "name"
  
  instance (FromJSON a) => FromJSON (JSONResponse a) where
    parseJSON = withObject "JSONResponse" objectParser
      where
        objectParser o =
          JSONResponse <$> o .:? "data" <*> o .:? "errors" .!= []
  
  data JSONResponse a = JSONResponse
    { responseData :: Maybe a,
      responseErrors :: [GQLError]
    }
    deriving (Generic, Show, ToJSON)
  