/* tslint:disable */
/* eslint-disable */

export type ValueTypes = {
    ["AccountGenderEnum"]:AccountGenderEnum;
	["AccountModel"]: AliasType<{
	_id?:true,
	organisationId?:true,
	createdAt?:true,
	updatedAt?:true,
	types?:true,
	organisationIds?:true,
	email?:true,
	userName?:true,
	firstName?:true,
	lastName?:true,
	profilePicture?:ValueTypes["ImageComponent"],
	phoneNumber?:true,
	gender?:true,
	age?:true,
	address?:ValueTypes["AddressComponent"],
	postCode?:true,
	children?:true,
	currentStage?:true,
	registerMessage?:true
		__typename?: true
}>;
	["AccountTypeEnum"]:AccountTypeEnum;
	["AddPeopleToRoomInput"]: {
	roomId:string,
	accountIds:string[]
};
	["AddressComponent"]: AliasType<{
	number?:true,
	street?:true,
	zip?:true,
	state?:true,
	city?:true,
	country?:true,
	loc?:true,
	formattedAddress?:true
		__typename?: true
}>;
	/** The javascript `Date` as string. Type represents date and time as the ISO Date string. */
["DateTime"]:unknown;
	["EditMessageInput"]: {
	message:string
};
	["GetArgs"]: {
	limit?:number,
	skip?:number,
	sort?:string
};
	["ImageComponent"]: AliasType<{
	large?:true,
	medium?:true,
	small?:true
		__typename?: true
}>;
	["ImageInput"]: {
	large:string,
	medium?:string,
	small?:string
};
	/** The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */
["JSONObject"]:unknown;
	["MessageModel"]: AliasType<{
	_id?:true,
	organisationId?:true,
	createdAt?:true,
	updatedAt?:true,
	roomId?:true,
	message?:true,
	edited?:true,
	deleted?:true,
	file?:ValueTypes["ImageComponent"],
	sentBy?:true,
	readBy?:ValueTypes["MessageReadBy"]
		__typename?: true
}>;
	["MessageReadBy"]: AliasType<{
	accountId?:true,
	readAt?:true
		__typename?: true
}>;
	["Mutation"]: AliasType<{
roomsCreateOne?: [{	input:ValueTypes["NewRoomInput"]},ValueTypes["RoomModel"]],
roomsAddPeople?: [{	input:ValueTypes["AddPeopleToRoomInput"]},ValueTypes["RoomModel"]],
roomsRemovePeople?: [{	input:ValueTypes["RemovePeopleFromRoomInput"]},ValueTypes["RoomModel"]],
roomsMarkAllMessageAsRead?: [{	roomId:string},ValueTypes["RoomModel"]],
roomsAddOneMessage?: [{	input:ValueTypes["NewMessageInput"]},ValueTypes["MessageModel"]],
roomsEditOneMessage?: [{	input:ValueTypes["EditMessageInput"],	id:string},ValueTypes["MessageModel"]],
roomsMarkMessageAsRead?: [{	id:string},ValueTypes["MessageModel"]],
roomsDeleteOneMessage?: [{	id:string},ValueTypes["MessageModel"]]
		__typename?: true
}>;
	["NewMessageInput"]: {
	roomId:string,
	message:string,
	file?:ValueTypes["ImageInput"]
};
	["NewRoomInput"]: {
	accountIds:string[]
};
	["Query"]: AliasType<{
roomsGetOne?: [{	id:string},ValueTypes["RoomModel"]],
roomsGetMany?: [{	pagination?:ValueTypes["GetArgs"]},ValueTypes["RoomModel"]]
		__typename?: true
}>;
	["RemovePeopleFromRoomInput"]: {
	roomId:string,
	accountIds:string[]
};
	["RoomModel"]: AliasType<{
	_id?:true,
	organisationId?:true,
	createdAt?:true,
	updatedAt?:true,
	title?:true,
	stats?:ValueTypes["RoomsStats"],
	getAccounts?:ValueTypes["AccountModel"],
getMessages?: [{	pagination?:ValueTypes["GetArgs"]},ValueTypes["MessageModel"]]
		__typename?: true
}>;
	["RoomsStats"]: AliasType<{
	unreadCounts?:ValueTypes["UnreadCount"]
		__typename?: true
}>;
	["StageEnum"]:StageEnum;
	["UnreadCount"]: AliasType<{
	accountId?:true,
	count?:true
		__typename?: true
}>
  }

export type PartialObjects = {
    ["AccountGenderEnum"]:AccountGenderEnum,
	["AccountModel"]: {
		__typename?: "AccountModel";
			_id?:string,
			organisationId?:string,
			createdAt?:PartialObjects["DateTime"],
			updatedAt?:PartialObjects["DateTime"],
			types?:PartialObjects["AccountTypeEnum"][],
			organisationIds?:string[],
			email?:string,
			userName?:string,
			firstName?:string,
			lastName?:string,
			profilePicture?:PartialObjects["ImageComponent"],
			phoneNumber?:string,
			gender?:PartialObjects["AccountGenderEnum"],
			age?:number,
			address?:PartialObjects["AddressComponent"],
			postCode?:number,
			children?:boolean,
			currentStage?:PartialObjects["StageEnum"],
			registerMessage?:string
	},
	["AccountTypeEnum"]:AccountTypeEnum,
	["AddPeopleToRoomInput"]: {
	roomId:string,
	accountIds:string[]
},
	["AddressComponent"]: {
		__typename?: "AddressComponent";
			number?:string,
			street?:string,
			zip?:string,
			state?:string,
			city?:string,
			country?:string,
			loc?:PartialObjects["JSONObject"],
			formattedAddress?:string
	},
	/** The javascript `Date` as string. Type represents date and time as the ISO Date string. */
["DateTime"]:any,
	["EditMessageInput"]: {
	message:string
},
	["GetArgs"]: {
	limit?:number,
	skip?:number,
	sort?:string
},
	["ImageComponent"]: {
		__typename?: "ImageComponent";
			large?:string,
			medium?:string,
			small?:string
	},
	["ImageInput"]: {
	large:string,
	medium?:string,
	small?:string
},
	/** The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */
["JSONObject"]:any,
	["MessageModel"]: {
		__typename?: "MessageModel";
			_id?:string,
			organisationId?:string,
			createdAt?:PartialObjects["DateTime"],
			updatedAt?:PartialObjects["DateTime"],
			roomId?:string,
			message?:string,
			edited?:boolean,
			deleted?:boolean,
			file?:PartialObjects["ImageComponent"],
			sentBy?:string,
			readBy?:PartialObjects["MessageReadBy"][]
	},
	["MessageReadBy"]: {
		__typename?: "MessageReadBy";
			accountId?:string,
			readAt?:PartialObjects["DateTime"]
	},
	["Mutation"]: {
		__typename?: "Mutation";
			roomsCreateOne?:PartialObjects["RoomModel"],
			roomsAddPeople?:PartialObjects["RoomModel"],
			roomsRemovePeople?:PartialObjects["RoomModel"],
			roomsMarkAllMessageAsRead?:PartialObjects["RoomModel"],
			roomsAddOneMessage?:PartialObjects["MessageModel"],
			roomsEditOneMessage?:PartialObjects["MessageModel"],
			roomsMarkMessageAsRead?:PartialObjects["MessageModel"],
			roomsDeleteOneMessage?:PartialObjects["MessageModel"]
	},
	["NewMessageInput"]: {
	roomId:string,
	message:string,
	file?:PartialObjects["ImageInput"]
},
	["NewRoomInput"]: {
	accountIds:string[]
},
	["Query"]: {
		__typename?: "Query";
			roomsGetOne?:PartialObjects["RoomModel"],
			roomsGetMany?:PartialObjects["RoomModel"][]
	},
	["RemovePeopleFromRoomInput"]: {
	roomId:string,
	accountIds:string[]
},
	["RoomModel"]: {
		__typename?: "RoomModel";
			_id?:string,
			organisationId?:string,
			createdAt?:PartialObjects["DateTime"],
			updatedAt?:PartialObjects["DateTime"],
			title?:string,
			stats?:PartialObjects["RoomsStats"],
			getAccounts?:PartialObjects["AccountModel"][],
			getMessages?:PartialObjects["MessageModel"][]
	},
	["RoomsStats"]: {
		__typename?: "RoomsStats";
			unreadCounts?:PartialObjects["UnreadCount"][]
	},
	["StageEnum"]:StageEnum,
	["UnreadCount"]: {
		__typename?: "UnreadCount";
			accountId?:string,
			count?:number
	}
  }

export enum AccountGenderEnum {
	m = "m",
	f = "f"
}

export type AccountModel = {
	__typename?: "AccountModel",
	_id:string,
	organisationId?:string,
	createdAt:DateTime,
	updatedAt:DateTime,
	types:AccountTypeEnum[],
	organisationIds?:string[],
	email:string,
	userName:string,
	firstName?:string,
	lastName?:string,
	profilePicture?:ImageComponent,
	phoneNumber?:string,
	gender:AccountGenderEnum,
	age:number,
	address?:AddressComponent,
	postCode:number,
	children:boolean,
	currentStage:StageEnum,
	registerMessage?:string
}

export enum AccountTypeEnum {
	admin = "admin",
	user = "user",
	blogAuthor = "blogAuthor"
}

export type AddPeopleToRoomInput = {
		roomId:string,
	accountIds:string[]
}

export type AddressComponent = {
	__typename?: "AddressComponent",
	number?:string,
	street?:string,
	zip:string,
	state?:string,
	city:string,
	country:string,
	loc?:JSONObject,
	formattedAddress?:string
}

/** The javascript `Date` as string. Type represents date and time as the ISO Date string. */
export type DateTime = any

export type EditMessageInput = {
		message:string
}

export type GetArgs = {
		limit?:number,
	skip?:number,
	sort?:string
}

export type ImageComponent = {
	__typename?: "ImageComponent",
	large:string,
	medium?:string,
	small?:string
}

export type ImageInput = {
		large:string,
	medium?:string,
	small?:string
}

/** The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */
export type JSONObject = any

export type MessageModel = {
	__typename?: "MessageModel",
	_id:string,
	organisationId?:string,
	createdAt:DateTime,
	updatedAt:DateTime,
	roomId:string,
	message:string,
	edited:boolean,
	deleted:boolean,
	file?:ImageComponent,
	sentBy:string,
	readBy:MessageReadBy[]
}

export type MessageReadBy = {
	__typename?: "MessageReadBy",
	accountId:string,
	readAt:DateTime
}

export type Mutation = {
	__typename?: "Mutation",
	roomsCreateOne:RoomModel,
	roomsAddPeople:RoomModel,
	roomsRemovePeople:RoomModel,
	roomsMarkAllMessageAsRead:RoomModel,
	roomsAddOneMessage:MessageModel,
	roomsEditOneMessage:MessageModel,
	roomsMarkMessageAsRead:MessageModel,
	roomsDeleteOneMessage:MessageModel
}

export type NewMessageInput = {
		roomId:string,
	message:string,
	file?:ImageInput
}

export type NewRoomInput = {
		accountIds:string[]
}

export type Query = {
	__typename?: "Query",
	roomsGetOne:RoomModel,
	roomsGetMany:RoomModel[]
}

export type RemovePeopleFromRoomInput = {
		roomId:string,
	accountIds:string[]
}

export type RoomModel = {
	__typename?: "RoomModel",
	_id:string,
	organisationId?:string,
	createdAt:DateTime,
	updatedAt:DateTime,
	title?:string,
	stats:RoomsStats,
	getAccounts?:AccountModel[],
	getMessages?:MessageModel[]
}

export type RoomsStats = {
	__typename?: "RoomsStats",
	unreadCounts:UnreadCount[]
}

export enum StageEnum {
	stage0 = "stage0",
	stage1 = "stage1",
	stage2 = "stage2",
	stage3 = "stage3",
	stage4 = "stage4"
}

export type UnreadCount = {
	__typename?: "UnreadCount",
	accountId:string,
	count:number
}

export const AllTypesProps: Record<string,any> = {
	AccountGenderEnum: "enum",
	AccountTypeEnum: "enum",
	AddPeopleToRoomInput:{
		roomId:{
			type:"String",
			array:false,
			arrayRequired:false,
			required:true
		},
		accountIds:{
			type:"String",
			array:true,
			arrayRequired:true,
			required:true
		}
	},
	DateTime: "String",
	EditMessageInput:{
		message:{
			type:"String",
			array:false,
			arrayRequired:false,
			required:true
		}
	},
	GetArgs:{
		limit:{
			type:"Int",
			array:false,
			arrayRequired:false,
			required:false
		},
		skip:{
			type:"Int",
			array:false,
			arrayRequired:false,
			required:false
		},
		sort:{
			type:"String",
			array:false,
			arrayRequired:false,
			required:false
		}
	},
	ImageInput:{
		large:{
			type:"String",
			array:false,
			arrayRequired:false,
			required:true
		},
		medium:{
			type:"String",
			array:false,
			arrayRequired:false,
			required:false
		},
		small:{
			type:"String",
			array:false,
			arrayRequired:false,
			required:false
		}
	},
	JSONObject: "String",
	Mutation:{
		roomsCreateOne:{
			input:{
				type:"NewRoomInput",
				array:false,
				arrayRequired:false,
				required:true
			}
		},
		roomsAddPeople:{
			input:{
				type:"AddPeopleToRoomInput",
				array:false,
				arrayRequired:false,
				required:true
			}
		},
		roomsRemovePeople:{
			input:{
				type:"RemovePeopleFromRoomInput",
				array:false,
				arrayRequired:false,
				required:true
			}
		},
		roomsMarkAllMessageAsRead:{
			roomId:{
				type:"String",
				array:false,
				arrayRequired:false,
				required:true
			}
		},
		roomsAddOneMessage:{
			input:{
				type:"NewMessageInput",
				array:false,
				arrayRequired:false,
				required:true
			}
		},
		roomsEditOneMessage:{
			input:{
				type:"EditMessageInput",
				array:false,
				arrayRequired:false,
				required:true
			},
			id:{
				type:"String",
				array:false,
				arrayRequired:false,
				required:true
			}
		},
		roomsMarkMessageAsRead:{
			id:{
				type:"String",
				array:false,
				arrayRequired:false,
				required:true
			}
		},
		roomsDeleteOneMessage:{
			id:{
				type:"String",
				array:false,
				arrayRequired:false,
				required:true
			}
		}
	},
	NewMessageInput:{
		roomId:{
			type:"String",
			array:false,
			arrayRequired:false,
			required:true
		},
		message:{
			type:"String",
			array:false,
			arrayRequired:false,
			required:true
		},
		file:{
			type:"ImageInput",
			array:false,
			arrayRequired:false,
			required:false
		}
	},
	NewRoomInput:{
		accountIds:{
			type:"String",
			array:true,
			arrayRequired:true,
			required:true
		}
	},
	Query:{
		roomsGetOne:{
			id:{
				type:"String",
				array:false,
				arrayRequired:false,
				required:true
			}
		},
		roomsGetMany:{
			pagination:{
				type:"GetArgs",
				array:false,
				arrayRequired:false,
				required:false
			}
		}
	},
	RemovePeopleFromRoomInput:{
		roomId:{
			type:"String",
			array:false,
			arrayRequired:false,
			required:true
		},
		accountIds:{
			type:"String",
			array:true,
			arrayRequired:true,
			required:true
		}
	},
	RoomModel:{
		getMessages:{
			pagination:{
				type:"GetArgs",
				array:false,
				arrayRequired:false,
				required:false
			}
		}
	},
	StageEnum: "enum"
}

export const ReturnTypes: Record<string,any> = {
	AccountModel:{
		_id:"ID",
		organisationId:"ID",
		createdAt:"DateTime",
		updatedAt:"DateTime",
		types:"AccountTypeEnum",
		organisationIds:"String",
		email:"String",
		userName:"String",
		firstName:"String",
		lastName:"String",
		profilePicture:"ImageComponent",
		phoneNumber:"String",
		gender:"AccountGenderEnum",
		age:"Int",
		address:"AddressComponent",
		postCode:"Int",
		children:"Boolean",
		currentStage:"StageEnum",
		registerMessage:"String"
	},
	AddressComponent:{
		number:"String",
		street:"String",
		zip:"String",
		state:"String",
		city:"String",
		country:"String",
		loc:"JSONObject",
		formattedAddress:"String"
	},
	ImageComponent:{
		large:"String",
		medium:"String",
		small:"String"
	},
	MessageModel:{
		_id:"ID",
		organisationId:"ID",
		createdAt:"DateTime",
		updatedAt:"DateTime",
		roomId:"String",
		message:"String",
		edited:"Boolean",
		deleted:"Boolean",
		file:"ImageComponent",
		sentBy:"String",
		readBy:"MessageReadBy"
	},
	MessageReadBy:{
		accountId:"String",
		readAt:"DateTime"
	},
	Mutation:{
		roomsCreateOne:"RoomModel",
		roomsAddPeople:"RoomModel",
		roomsRemovePeople:"RoomModel",
		roomsMarkAllMessageAsRead:"RoomModel",
		roomsAddOneMessage:"MessageModel",
		roomsEditOneMessage:"MessageModel",
		roomsMarkMessageAsRead:"MessageModel",
		roomsDeleteOneMessage:"MessageModel"
	},
	Query:{
		roomsGetOne:"RoomModel",
		roomsGetMany:"RoomModel"
	},
	RoomModel:{
		_id:"ID",
		organisationId:"ID",
		createdAt:"DateTime",
		updatedAt:"DateTime",
		title:"String",
		stats:"RoomsStats",
		getAccounts:"AccountModel",
		getMessages:"MessageModel"
	},
	RoomsStats:{
		unreadCounts:"UnreadCount"
	},
	UnreadCount:{
		accountId:"String",
		count:"Float"
	}
}

export class GraphQLError extends Error {
    constructor(public response: GraphQLResponse) {
      super("");
      console.error(response);
    }
    toString() {
      return "GraphQL Response Error";
    }
  }


type Func<P extends any[], R> = (...args: P) => R;
type AnyFunc = Func<any, any>;

type WithTypeNameValue<T> = T & {
  __typename?: true;
};

type AliasType<T> = WithTypeNameValue<T> & {
  __alias?: Record<string, WithTypeNameValue<T>>;
};

type NotUndefined<T> = T extends undefined ? never : T;

export type ResolverType<F> = NotUndefined<F extends [infer ARGS, any] ? ARGS : undefined>;

export type ArgsType<F extends AnyFunc> = F extends Func<infer P, any> ? P : never;

interface GraphQLResponse {
  data?: Record<string, any>;
  errors?: Array<{
    message: string;
  }>;
}
export type MapInterface<SRC, DST> = SRC extends {
  __interface: infer INTERFACE;
  __resolve: infer IMPLEMENTORS;
}
  ? ObjectToUnion<
      Omit<
        {
          [Key in keyof Omit<DST, keyof INTERFACE | '__typename'>]: Key extends keyof IMPLEMENTORS
            ? MapType<IMPLEMENTORS[Key], DST[Key]> &
                Omit<
                  {
                    [Key in keyof Omit<
                      DST,
                      keyof IMPLEMENTORS | '__typename'
                    >]: Key extends keyof INTERFACE
                      ? LastMapTypeSRCResolver<INTERFACE[Key], DST[Key]>
                      : never;
                  },
                  keyof IMPLEMENTORS
                > &
                (DST extends { __typename: any }
                  ? MapType<IMPLEMENTORS[Key], { __typename: true }>
                  : {})
            : never;
        },
        keyof INTERFACE | '__typename'
      >
    >
  : never;

export type ValueToUnion<T> = T extends {
  __typename: infer R;
}
  ? {
      [P in keyof Omit<T, '__typename'>]: T[P] & {
        __typename: R;
      };
    }
  : T;

export type ObjectToUnion<T> = {
  [P in keyof T]: T[P];
}[keyof T];

type Anify<T> = { [P in keyof T]?: any };


type LastMapTypeSRCResolver<SRC, DST> = SRC extends undefined
  ? undefined
  : SRC extends Array<infer AR>
  ? LastMapTypeSRCResolver<AR, DST>[]
  : SRC extends { __interface: any; __resolve: any }
  ? MapInterface<SRC, DST>
  : SRC extends { __union: any; __resolve: infer RESOLVE }
  ? ObjectToUnion<MapType<RESOLVE, ValueToUnion<DST>>>
  : DST extends boolean
  ? SRC
  : MapType<SRC, DST>;

type MapType<SRC extends Anify<DST>, DST> = DST extends boolean
  ? SRC
  : DST extends {
      __alias: any;
    }
  ? {
      [A in keyof DST["__alias"]]: Required<SRC> extends Anify<
        DST["__alias"][A]
      >
        ? MapType<Required<SRC>, DST["__alias"][A]>
        : never;
    } &
      {
        [Key in keyof Omit<DST, "__alias">]: DST[Key] extends [
          any,
          infer PAYLOAD
        ]
          ? LastMapTypeSRCResolver<SRC[Key], PAYLOAD>
          : LastMapTypeSRCResolver<SRC[Key], DST[Key]>;
      }
  : {
      [Key in keyof DST]: DST[Key] extends [any, infer PAYLOAD]
        ? LastMapTypeSRCResolver<SRC[Key], PAYLOAD>
        : LastMapTypeSRCResolver<SRC[Key], DST[Key]>;
    };

type OperationToGraphQL<V, T> = <Z extends V>(o: Z | V, variables?: Record<string, any>) => Promise<MapType<T, Z>>;

type CastToGraphQL<V, T> = (
  resultOfYourQuery: any
) => <Z extends V>(o: Z | V) => MapType<T, Z>;

type fetchOptions = ArgsType<typeof fetch>;

export type SelectionFunction<V> = <T>(t: T | V) => T;
type FetchFunction = (query: string, variables?: Record<string, any>) => any;



export const ZeusSelect = <T>() => ((t: any) => t) as SelectionFunction<T>;
export const ScalarResolver = (scalar: string, value: any) => {
  switch (scalar) {
    case 'String':
      return  `"${value.replace(/"/g, '\\\"')}"`;
    case 'Int':
      return `${value}`;
    case 'Float':
      return `${value}`;
    case 'Boolean':
      return `${value}`;
    case 'ID':
      return `"${value}"`;
    case 'enum':
      return `${value}`;
    case 'scalar':
      return `${value}`;
    default:
      return false;
  }
};

export const TypesPropsResolver = ({
  value,
  type,
  name,
  key,
  blockArrays
}: {
  value: any;
  type: string;
  name: string;
  key?: string;
  blockArrays?: boolean;
}): string => {
  if (value === null) {
    return `null`;
  }
  let resolvedValue = AllTypesProps[type][name];
  if (key) {
    resolvedValue = resolvedValue[key];
  }
  if (!resolvedValue) {
    throw new Error(`Cannot resolve ${type} ${name}${key ? ` ${key}` : ''}`)
  }
  const typeResolved = resolvedValue.type;
  const isArray: boolean = resolvedValue.array;
  if (typeof value === 'string' && value.startsWith(`ZEUS_VAR$`)) {
    const isRequired = resolvedValue.required ? '!' : ''
    return `\$${value.split(`ZEUS_VAR$`)[1]}__ZEUS_VAR__${typeResolved}${isRequired}`;
  }
  if (isArray && !blockArrays) {
    return `[${value
      .map((v: any) => TypesPropsResolver({ value: v, type, name, key, blockArrays: true }))
      .join(',')}]`;
  }
  const reslovedScalar = ScalarResolver(typeResolved, value);
  if (!reslovedScalar) {
    const resolvedType = AllTypesProps[typeResolved];
    if (typeof resolvedType === 'object') {
      const argsKeys = Object.keys(resolvedType);
      return `{${argsKeys
        .filter((ak) => value[ak] !== undefined)
        .map(
          (ak) => `${ak}:${TypesPropsResolver({ value: value[ak], type: typeResolved, name: ak })}`
        )}}`;
    }
    return ScalarResolver(AllTypesProps[typeResolved], value) as string;
  }
  return reslovedScalar;
};

const isArrayFunction = (
  parent: string[],
  a: any[]
) => {
  const [values, r] = a;
  const [mainKey, key, ...keys] = parent;
  const keyValues = Object.keys(values);

  if (!keys.length) {
      return keyValues.length > 0
        ? `(${keyValues
            .map(
              (v) =>
                `${v}:${TypesPropsResolver({
                  value: values[v],
                  type: mainKey,
                  name: key,
                  key: v
                })}`
            )
            .join(',')})${r ? traverseToSeekArrays(parent, r) : ''}`
        : traverseToSeekArrays(parent, r);
    }

  const [typeResolverKey] = keys.splice(keys.length - 1, 1);
  let valueToResolve = ReturnTypes[mainKey][key];
  for (const k of keys) {
    valueToResolve = ReturnTypes[valueToResolve][k];
  }

  const argumentString =
    keyValues.length > 0
      ? `(${keyValues
          .map(
            (v) =>
              `${v}:${TypesPropsResolver({
                value: values[v],
                type: valueToResolve,
                name: typeResolverKey,
                key: v
              })}`
          )
          .join(',')})${r ? traverseToSeekArrays(parent, r) : ''}`
      : traverseToSeekArrays(parent, r);
  return argumentString;
};

const resolveKV = (k: string, v: boolean | string | { [x: string]: boolean | string }) =>
  typeof v === 'boolean' ? k : typeof v === 'object' ? `${k}{${objectToTree(v)}}` : `${k}${v}`;

const objectToTree = (o: { [x: string]: boolean | string }): string =>
  `{${Object.keys(o).map((k) => `${resolveKV(k, o[k])}`).join(' ')}}`;

const traverseToSeekArrays = (parent: string[], a?: any): string => {
  if (!a) return '';
  if (Object.keys(a).length === 0) {
    return '';
  }
  let b: Record<string, any> = {};
  if (Array.isArray(a)) {
    return isArrayFunction([...parent], a);
  } else {
    if (typeof a === 'object') {
      Object.keys(a).map((k) => {
        if (k === '__alias') {
          Object.keys(a[k]).map((aliasKey) => {
            const aliasOperations = a[k][aliasKey];
            const aliasOperationName = Object.keys(aliasOperations)[0];
            const aliasOperation = aliasOperations[aliasOperationName];
            b[
              `${aliasOperationName}__alias__${aliasKey}: ${aliasOperationName}`
            ] = traverseToSeekArrays([...parent, aliasOperationName], aliasOperation);
          });
        } else {
          b[k] = traverseToSeekArrays([...parent, k], a[k]);
        }
      });
    } else {
      return '';
    }
  }
  return objectToTree(b);
};

const buildQuery = (type: string, a?: Record<any, any>) => traverseToSeekArrays([type], a);

const inspectVariables = (query: string) => {
  const regex = /\$\b\w*ZEUS_VAR\w*\b[!]?/g;
  let result;
  const AllVariables = [];
  while ((result = regex.exec(query))) {
    AllVariables.push(result[0]);
  }
  if (!AllVariables.length) {
    return query;
  }
  let filteredQuery = query;
  AllVariables.forEach((variable) => {
    filteredQuery = filteredQuery.replace(variable, variable.split('__ZEUS_VAR__')[0]);
  });
  return `(${AllVariables.map((a) => a.split('__ZEUS_VAR__'))
    .map(([variableName, variableType]) => `${variableName}:${variableType}`)
    .join(', ')})${filteredQuery}`;
};

const queryConstruct = (t: 'query' | 'mutation' | 'subscription', tName: string) => (o: Record<any, any>) =>
  `${t.toLowerCase()}${inspectVariables(buildQuery(tName, o))}`;
  
const fullChainConstruct = (fn: FetchFunction) => (t: 'query' | 'mutation' | 'subscription', tName: string) => (
  o: Record<any, any>,
  variables?: Record<string, any>,
) => fn(queryConstruct(t, tName)(o), variables);

const seekForAliases = (o: any) => {
  if (typeof o === 'object' && o) {
    const keys = Object.keys(o);
    if (keys.length < 1) {
      return;
    }
    keys.forEach((k) => {
      const value = o[k];
      if (k.indexOf('__alias__') !== -1) {
        const [operation, alias] = k.split('__alias__');
        o[alias] = {
          [operation]: value
        };
        delete o[k];
      } else {
        if (Array.isArray(value)) {
          value.forEach(seekForAliases);
        } else {
          if (typeof value === 'object') {
            seekForAliases(value);
          }
        }
      }
    });
  }
};

export const $ = (t: TemplateStringsArray): any => `ZEUS_VAR$${t.join('')}`;


const handleFetchResponse = (
  response: Parameters<Extract<Parameters<ReturnType<typeof fetch>['then']>[0], Function>>[0]
): Promise<GraphQLResponse> => {
  if (!response.ok) {
    return new Promise((resolve, reject) => {
      response.text().then(text => {
        try { reject(JSON.parse(text)); }
        catch (err) { reject(text); }
      }).catch(reject);
    });
  }
  return response.json();
};

const apiFetch = (options: fetchOptions) => (query: string, variables: Record<string, any> = {}) => {
    let fetchFunction = fetch;
    let queryString = query;
    let fetchOptions = options[1] || {};
    if (fetchOptions.method && fetchOptions.method === 'GET') {
      queryString = encodeURIComponent(query);
      return fetchFunction(`${options[0]}?query=${queryString}`, fetchOptions)
        .then(handleFetchResponse)
        .then((response: GraphQLResponse) => {
          if (response.errors) {
            throw new GraphQLError(response);
          }
          seekForAliases(response.data);
          return response.data;
        });
    }
    return fetchFunction(`${options[0]}`, {
      body: JSON.stringify({ query: queryString, variables }),
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      ...fetchOptions
    })
      .then(handleFetchResponse)
      .then((response: GraphQLResponse) => {
        if (response.errors) {
          throw new GraphQLError(response);
        }
        seekForAliases(response.data);
        return response.data;
      });
  };
  


export const Thunder = (fn: FetchFunction) => ({
  query: ((o: any, variables) =>
    fullChainConstruct(fn)('query', 'Query')(o, variables).then(
      (response: any) => response
    )) as OperationToGraphQL<ValueTypes["Query"],Query>,
mutation: ((o: any, variables) =>
    fullChainConstruct(fn)('mutation', 'Mutation')(o, variables).then(
      (response: any) => response
    )) as OperationToGraphQL<ValueTypes["Mutation"],Mutation>
});

export const Chain = (...options: fetchOptions) => ({
  query: ((o: any, variables) =>
    fullChainConstruct(apiFetch(options))('query', 'Query')(o, variables).then(
      (response: any) => response
    )) as OperationToGraphQL<ValueTypes["Query"],Query>,
mutation: ((o: any, variables) =>
    fullChainConstruct(apiFetch(options))('mutation', 'Mutation')(o, variables).then(
      (response: any) => response
    )) as OperationToGraphQL<ValueTypes["Mutation"],Mutation>
});
export const Zeus = {
  query: (o:ValueTypes["Query"]) => queryConstruct('query', 'Query')(o),
mutation: (o:ValueTypes["Mutation"]) => queryConstruct('mutation', 'Mutation')(o)
};
export const Cast = {
  query: ((o: any) => (b: any) => o) as CastToGraphQL<
  ValueTypes["Query"],
  Query
>,
mutation: ((o: any) => (b: any) => o) as CastToGraphQL<
  ValueTypes["Mutation"],
  Mutation
>
};
export const Selectors = {
  query: ZeusSelect<ValueTypes["Query"]>(),
mutation: ZeusSelect<ValueTypes["Mutation"]>()
};
  

export const Gql = Chain('https://80fbnw62ql.execute-api.eu-central-1.amazonaws.com/dev')