"use strict";
const graphql = require("graphql");
const forEachState = require("./forEachState.js");
function getTypeInfo(schema, tokenState) {
  const info = {
    schema,
    type: null,
    parentType: null,
    inputType: null,
    directiveDef: null,
    fieldDef: null,
    argDef: null,
    argDefs: null,
    objectFieldDefs: null
  };
  forEachState.forEachState(tokenState, (state) => {
    var _a, _b;
    switch (state.kind) {
      case "Query":
      case "ShortQuery":
        info.type = schema.getQueryType();
        break;
      case "Mutation":
        info.type = schema.getMutationType();
        break;
      case "Subscription":
        info.type = schema.getSubscriptionType();
        break;
      case "InlineFragment":
      case "FragmentDefinition":
        if (state.type) {
          info.type = schema.getType(state.type);
        }
        break;
      case "Field":
      case "AliasedField":
        info.fieldDef = info.type && state.name ? getFieldDef(schema, info.parentType, state.name) : null;
        info.type = (_a = info.fieldDef) === null || _a === void 0 ? void 0 : _a.type;
        break;
      case "SelectionSet":
        info.parentType = info.type ? graphql.getNamedType(info.type) : null;
        break;
      case "Directive":
        info.directiveDef = state.name ? schema.getDirective(state.name) : null;
        break;
      case "Arguments":
        const parentDef = state.prevState ? state.prevState.kind === "Field" ? info.fieldDef : state.prevState.kind === "Directive" ? info.directiveDef : state.prevState.kind === "AliasedField" ? state.prevState.name && getFieldDef(schema, info.parentType, state.prevState.name) : null : null;
        info.argDefs = parentDef ? parentDef.args : null;
        break;
      case "Argument":
        info.argDef = null;
        if (info.argDefs) {
          for (let i = 0; i < info.argDefs.length; i++) {
            if (info.argDefs[i].name === state.name) {
              info.argDef = info.argDefs[i];
              break;
            }
          }
        }
        info.inputType = (_b = info.argDef) === null || _b === void 0 ? void 0 : _b.type;
        break;
      case "EnumValue":
        const enumType = info.inputType ? graphql.getNamedType(info.inputType) : null;
        info.enumValue = enumType instanceof graphql.GraphQLEnumType ? find(enumType.getValues(), (val) => val.value === state.name) : null;
        break;
      case "ListValue":
        const nullableType = info.inputType ? graphql.getNullableType(info.inputType) : null;
        info.inputType = nullableType instanceof graphql.GraphQLList ? nullableType.ofType : null;
        break;
      case "ObjectValue":
        const objectType = info.inputType ? graphql.getNamedType(info.inputType) : null;
        info.objectFieldDefs = objectType instanceof graphql.GraphQLInputObjectType ? objectType.getFields() : null;
        break;
      case "ObjectField":
        const objectField = state.name && info.objectFieldDefs ? info.objectFieldDefs[state.name] : null;
        info.inputType = objectField === null || objectField === void 0 ? void 0 : objectField.type;
        info.fieldDef = objectField;
        break;
      case "NamedType":
        info.type = state.name ? schema.getType(state.name) : null;
        break;
    }
  });
  return info;
}
function getFieldDef(schema, type, fieldName) {
  if (fieldName === graphql.SchemaMetaFieldDef.name && schema.getQueryType() === type) {
    return graphql.SchemaMetaFieldDef;
  }
  if (fieldName === graphql.TypeMetaFieldDef.name && schema.getQueryType() === type) {
    return graphql.TypeMetaFieldDef;
  }
  if (fieldName === graphql.TypeNameMetaFieldDef.name && graphql.isCompositeType(type)) {
    return graphql.TypeNameMetaFieldDef;
  }
  if (type && type.getFields) {
    return type.getFields()[fieldName];
  }
}
function find(array, predicate) {
  for (let i = 0; i < array.length; i++) {
    if (predicate(array[i])) {
      return array[i];
    }
  }
}
function getFieldReference(typeInfo) {
  return {
    kind: "Field",
    schema: typeInfo.schema,
    field: typeInfo.fieldDef,
    type: isMetaField(typeInfo.fieldDef) ? null : typeInfo.parentType
  };
}
function getDirectiveReference(typeInfo) {
  return {
    kind: "Directive",
    schema: typeInfo.schema,
    directive: typeInfo.directiveDef
  };
}
function getArgumentReference(typeInfo) {
  return typeInfo.directiveDef ? {
    kind: "Argument",
    schema: typeInfo.schema,
    argument: typeInfo.argDef,
    directive: typeInfo.directiveDef
  } : {
    kind: "Argument",
    schema: typeInfo.schema,
    argument: typeInfo.argDef,
    field: typeInfo.fieldDef,
    type: isMetaField(typeInfo.fieldDef) ? null : typeInfo.parentType
  };
}
function getEnumValueReference(typeInfo) {
  return {
    kind: "EnumValue",
    value: typeInfo.enumValue || void 0,
    type: typeInfo.inputType ? graphql.getNamedType(typeInfo.inputType) : void 0
  };
}
function getTypeReference(typeInfo, type) {
  return {
    kind: "Type",
    schema: typeInfo.schema,
    type: type || typeInfo.type
  };
}
function isMetaField(fieldDef) {
  return fieldDef.name.slice(0, 2) === "__";
}
exports.getArgumentReference = getArgumentReference;
exports.getDirectiveReference = getDirectiveReference;
exports.getEnumValueReference = getEnumValueReference;
exports.getFieldReference = getFieldReference;
exports.getTypeInfo = getTypeInfo;
exports.getTypeReference = getTypeReference;
//# sourceMappingURL=SchemaReference.js.map
