const createIdFilters = require('./filters/idFilters')
const createStringFilters = require('./filters/stringFilters')
const createFloatFilters = require('./filters/floatFilters')
const createIntegerFilters = require('./filters/integerFilters')
const createBooleanFilters = require('./filters/booleanFilters')
const createDatetimeFilters = require('./filters/datetimeFilters')
const createDateFilters = require('./filters/dateFilters')
const createDocumentFilters = require('./filters/documentFilters')

const typeAliases = {
  Url: 'String',
  Text: 'String',
  Email: 'String'
}

const filterCreators = {
  ID: createIdFilters,
  String: createStringFilters,
  Float: createFloatFilters,
  Integer: createIntegerFilters,
  Boolean: createBooleanFilters,
  Datetime: createDatetimeFilters,
  Date: createDateFilters,
  Document: createDocumentFilters
}

function generateTypeFilters(types) {
  const builtInTypeKeys = Object.keys(filterCreators)
  const builtinTypeValues = Object.values(filterCreators)
  const objectTypes = types.filter(
    type =>
      type.type === 'Object' &&
      !['Block', 'Span'].includes(type.name) && // TODO: What do we do with blocks?
      !type.interfaces &&
      !builtInTypeKeys.includes(type.type)
  )
  const documentTypes = types.filter(
    type => type.type === 'Object' && type.interfaces && type.interfaces.includes('Document')
  )

  const builtinTypeFilters = createBuiltinTypeFilters(builtinTypeValues)
  const objectTypeFilters = createObjectTypeFilters(objectTypes)
  const documentTypeFilters = createDocumentTypeFilters(documentTypes)

  return builtinTypeFilters.concat(objectTypeFilters).concat(documentTypeFilters)
}

function createBuiltinTypeFilters(builtinTypeValues) {
  return builtinTypeValues.map(filterCreator => filterCreator())
}

function createObjectTypeFilters(objectTypes) {
  return objectTypes.map(objectType => {
    return {
      name: `${objectType.name}Filter`,
      kind: 'InputObject',
      fields: createFieldFilters(objectType)
    }
  })
}

function createDocumentTypeFilters(documentTypes) {
  return documentTypes.map(documentType => {
    const fields = getDocumentFilters().concat(createFieldFilters(documentType))
    return {
      name: `${documentType.name}Filter`,
      kind: 'InputObject',
      fields
    }
  })
}

function createFieldFilters(objectType) {
  return objectType.fields
    .filter(field => field.type !== 'JSON' && field.kind !== 'List')
    .map(field => ({
      fieldName: field.fieldName,
      type: `${typeAliases[field.type] || field.type}Filter`,
      isReference: field.isReference
    }))
}

function getDocumentFilters() {
  return [
    {
      fieldName: '_',
      type: 'DocumentFilter',
      description: 'Apply filters on document level'
    }
  ]
}

module.exports = generateTypeFilters

@@ -1233,16 +1233,105 @@
 ype)%0A  )
+%0A%0A  const unionTypes = types.filter(type =%3E type.kind === 'Union').map(type =%3E type.name)
 %0A  const
@@ -1596,16 +1596,30 @@
 ectTypes
+, %7BunionTypes%7D
 )%0A  cons
@@ -1681,16 +1681,30 @@
 entTypes
+, %7BunionTypes%7D
 )%0A%0A  ret
@@ -1946,24 +1946,33 @@
 (objectTypes
+, options
 ) %7B%0A  return
@@ -2127,16 +2127,25 @@
 jectType
+, options
 )%0A    %7D%0A
@@ -2196,24 +2196,33 @@
 ocumentTypes
+, options
 ) %7B%0A  return
@@ -2336,16 +2336,25 @@
 mentType
+, options
 ))%0A    r
@@ -2495,19 +2495,59 @@
 jectType
-) %7B
+, options) %7B%0A  const %7BunionTypes%7D = options
 %0A  retur
@@ -2578,16 +2578,23 @@
 .filter(
+%0A      
 field =%3E
@@ -2640,16 +2640,57 @@
 = 'List'
+ && !unionTypes.includes(field.type)%0A    
 )%0A    .m

Exclude unions from filter generation