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

export type ValueTypes = {
    ["AccountGenderEnum"]:AccountGenderEnum;
	["AccountModel"]: AliasType<{
	_id?:true,
	organisationId?:true,
	createdBy?:true,
	updatedBy?:true,
	deletedBy?:true,
	createdAt?:true,
	updatedAt?:true,
	r?:true,
	w?:true,
	d?:true,
	types?:true,
	organisationIds?:true,
	email?:true,
	userName?:true,
	firstName?:true,
	lastName?:true,
	profilePicture?:ValueTypes["ImageComponent"],
	phoneNumber?:true,
	gender?:true,
	birthDate?:true,
	getAge?:true,
	address?:ValueTypes["AddressComponent"],
	language?:true,
	settings?:ValueTypes["SettingsComponent"],
	securityCheck?:true,
	organisation?:true,
	position?:true,
	profileCompleted?:true,
		__typename?: true
}>;
	["AccountTypeEnum"]:AccountTypeEnum;
	["AddressComponent"]: AliasType<{
	number?:true,
	street?:true,
	streetBis?:true,
	floor?:true,
	box?:true,
	zip?:true,
	state?:true,
	city?:true,
	country?:true,
		__typename?: true
}>;
	["AvailableTranslation"]:AvailableTranslation;
	/** The javascript `Date` as string. Type represents date and time as the ISO Date string. */
["DateTime"]:unknown;
	["EngineFileInitOutput"]: AliasType<{
	uploadUrl?:true,
	file?:ValueTypes["EngineFileSchema"],
		__typename?: true
}>;
	["EngineFileSchema"]: AliasType<{
	accountId?:true,
	mime?:true,
	fileName?:true,
	fileNameMedium?:true,
	fileNameSmall?:true,
	large?:true,
	medium?:true,
	small?:true,
	account?:ValueTypes["AccountModel"],
	_id?:true,
	organisationId?:true,
	paths?:ValueTypes["EnginePathComponent"],
	by?:ValueTypes["MetaBy"],
	permissions?:ValueTypes["MetaPermissions"],
	createdAt?:true,
	updatedAt?:true,
	tagsIds?:true,
	getTags?:ValueTypes["TagSchema"],
getUrl?: [{	size?:ValueTypes["FileSize"]},true],
		__typename?: true
}>;
	["EnginePathComponent"]: AliasType<{
	ressourceModel?:true,
	ressourceId?:true,
		__typename?: true
}>;
	["FileSize"]:FileSize;
	["FilesRessourceEnum"]:FilesRessourceEnum;
	["GetArgs"]: {
	limit:number,
	skip:number,
	sort?:string
};
	["IEngineSchema"]:AliasType<{
		_id?:true,
	organisationId?:true,
	paths?:ValueTypes["EnginePathComponent"],
	by?:ValueTypes["MetaBy"],
	permissions?:ValueTypes["MetaPermissions"],
	createdAt?:true,
	updatedAt?:true,
	tagsIds?:true;
		['...on EngineFileSchema']?: Omit<ValueTypes["EngineFileSchema"],keyof ValueTypes["IEngineSchema"]>;
		['...on TagSchema']?: Omit<ValueTypes["TagSchema"],keyof ValueTypes["IEngineSchema"]>;
		__typename?: true
}>;
	["ImageComponent"]: AliasType<{
	title?:true,
	fileType?:true,
	large?:true,
	medium?:true,
	small?:true,
		__typename?: true
}>;
	["MetaBy"]: AliasType<{
	createdBy?:true,
	updatedBy?:true,
	deletedBy?:true,
		__typename?: true
}>;
	["MetaPermissions"]: AliasType<{
	r?:true,
	w?:true,
	d?:true,
		__typename?: true
}>;
	["ModelLoadersEnum"]:ModelLoadersEnum;
	["Mutation"]: AliasType<{
filesInitUpload?: [{	input:ValueTypes["NewFileUploadInitInput"]},ValueTypes["EngineFileInitOutput"]],
		__typename?: true
}>;
	["NewFileUploadInitInput"]: {
	ressourceModel?:ValueTypes["FilesRessourceEnum"],
	ressourceId?:string,
	fileName:string,
	privateFile?:boolean,
	tagsIds?:string[]
};
	["Query"]: AliasType<{
filesGetMine?: [{	pagination?:ValueTypes["GetArgs"],	sharedWith?:string,	tagsIds?:string[],	search?:string},ValueTypes["EngineFileSchema"]],
filesGetMineCount?: [{	pagination?:ValueTypes["GetArgs"],	sharedWith?:string,	tagsIds?:string[],	search?:string},ValueTypes["EngineFileSchema"]],
filesGetSharedWithMe?: [{	pagination?:ValueTypes["GetArgs"],	sharedWith?:string,	tagsIds?:string[],	search?:string},ValueTypes["EngineFileSchema"]],
filesGetSharedWithMeCount?: [{	pagination?:ValueTypes["GetArgs"],	sharedWith?:string,	tagsIds?:string[],	search?:string},ValueTypes["EngineFileSchema"]],
filesGetOne?: [{	id:string},ValueTypes["EngineFileSchema"]],
		__typename?: true
}>;
	["SettingsComponent"]: AliasType<{
	type?:true,
	email?:true,
	pushNotifications?:true,
	sms?:true,
		__typename?: true
}>;
	["SettingsTypeEnum"]:SettingsTypeEnum;
	["TagSchema"]: AliasType<{
	title?:true,
	_id?:true,
	organisationId?:true,
	paths?:ValueTypes["EnginePathComponent"],
	by?:ValueTypes["MetaBy"],
	permissions?:ValueTypes["MetaPermissions"],
	createdAt?:true,
	updatedAt?:true,
	tagsIds?:true,
		__typename?: true
}>
  }

export type PartialObjects = {
    ["AccountGenderEnum"]:AccountGenderEnum,
	["AccountModel"]: {
		__typename?: "AccountModel";
			_id?:string,
			organisationId?:string,
			createdBy?:string,
			updatedBy?:string,
			deletedBy?:string,
			createdAt?:PartialObjects["DateTime"],
			updatedAt?:PartialObjects["DateTime"],
			r?:string[],
			w?:string[],
			d?:string[],
			types?:PartialObjects["AccountTypeEnum"][],
			organisationIds?:string[],
			email?:string,
			userName?:string,
			firstName?:string,
			lastName?:string,
			profilePicture?:PartialObjects["ImageComponent"],
			phoneNumber?:string,
			gender?:PartialObjects["AccountGenderEnum"],
			birthDate?:PartialObjects["DateTime"],
			getAge?:number,
			address?:PartialObjects["AddressComponent"],
			language?:PartialObjects["AvailableTranslation"],
			settings?:PartialObjects["SettingsComponent"][],
			securityCheck?:boolean,
			organisation?:string,
			position?:string,
			profileCompleted?:boolean
	},
	["AccountTypeEnum"]:AccountTypeEnum,
	["AddressComponent"]: {
		__typename?: "AddressComponent";
			number?:string,
			street?:string,
			streetBis?:string,
			floor?:string,
			box?:string,
			zip?:string,
			state?:string,
			city?:string,
			country?:string
	},
	["AvailableTranslation"]:AvailableTranslation,
	/** The javascript `Date` as string. Type represents date and time as the ISO Date string. */
["DateTime"]:any,
	["EngineFileInitOutput"]: {
		__typename?: "EngineFileInitOutput";
			uploadUrl?:string,
			file?:PartialObjects["EngineFileSchema"]
	},
	["EngineFileSchema"]: {
		__typename?: "EngineFileSchema";
			accountId?:string,
			mime?:string,
			fileName?:string,
			fileNameMedium?:string,
			fileNameSmall?:string,
			large?:string,
			medium?:string,
			small?:string,
			account?:PartialObjects["AccountModel"],
			_id?:string,
			organisationId?:string,
			paths?:PartialObjects["EnginePathComponent"][],
			by?:PartialObjects["MetaBy"],
			permissions?:PartialObjects["MetaPermissions"],
			createdAt?:PartialObjects["DateTime"],
			updatedAt?:PartialObjects["DateTime"],
			tagsIds?:string[],
			getTags?:PartialObjects["TagSchema"][],
			getUrl?:string
	},
	["EnginePathComponent"]: {
		__typename?: "EnginePathComponent";
			ressourceModel?:PartialObjects["ModelLoadersEnum"],
			ressourceId?:string
	},
	["FileSize"]:FileSize,
	["FilesRessourceEnum"]:FilesRessourceEnum,
	["GetArgs"]: {
	limit:number,
	skip:number,
	sort?:string
},
	["IEngineSchema"]:{
		_id?:string;
	organisationId?:string;
	paths?:PartialObjects["EnginePathComponent"][];
	by?:PartialObjects["MetaBy"];
	permissions?:PartialObjects["MetaPermissions"];
	createdAt?:PartialObjects["DateTime"];
	updatedAt?:PartialObjects["DateTime"];
	tagsIds?:string[]
} & (PartialObjects["EngineFileSchema"] | PartialObjects["TagSchema"]),
	["ImageComponent"]: {
		__typename?: "ImageComponent";
			title?:string,
			fileType?:string,
			large?:string,
			medium?:string,
			small?:string
	},
	["MetaBy"]: {
		__typename?: "MetaBy";
			createdBy?:string,
			updatedBy?:string,
			deletedBy?:string
	},
	["MetaPermissions"]: {
		__typename?: "MetaPermissions";
			r?:string[],
			w?:string[],
			d?:string[]
	},
	["ModelLoadersEnum"]:ModelLoadersEnum,
	["Mutation"]: {
		__typename?: "Mutation";
			filesInitUpload?:PartialObjects["EngineFileInitOutput"]
	},
	["NewFileUploadInitInput"]: {
	ressourceModel?:PartialObjects["FilesRessourceEnum"],
	ressourceId?:string,
	fileName:string,
	privateFile?:boolean,
	tagsIds?:string[]
},
	["Query"]: {
		__typename?: "Query";
			filesGetMine?:PartialObjects["EngineFileSchema"][],
			filesGetMineCount?:PartialObjects["EngineFileSchema"][],
			filesGetSharedWithMe?:PartialObjects["EngineFileSchema"][],
			filesGetSharedWithMeCount?:PartialObjects["EngineFileSchema"][],
			filesGetOne?:PartialObjects["EngineFileSchema"]
	},
	["SettingsComponent"]: {
		__typename?: "SettingsComponent";
			type?:PartialObjects["SettingsTypeEnum"],
			email?:boolean,
			pushNotifications?:boolean,
			sms?:boolean
	},
	["SettingsTypeEnum"]:SettingsTypeEnum,
	["TagSchema"]: {
		__typename?: "TagSchema";
			title?:string,
			_id?:string,
			organisationId?:string,
			paths?:PartialObjects["EnginePathComponent"][],
			by?:PartialObjects["MetaBy"],
			permissions?:PartialObjects["MetaPermissions"],
			createdAt?:PartialObjects["DateTime"],
			updatedAt?:PartialObjects["DateTime"],
			tagsIds?:string[]
	}
  }

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

export type AccountModel = {
	__typename?: "AccountModel",
	_id:string,
	organisationId?:string,
	createdBy?:string,
	updatedBy?:string,
	deletedBy?:string,
	createdAt:DateTime,
	updatedAt:DateTime,
	r:string[],
	w:string[],
	d:string[],
	types:AccountTypeEnum[],
	organisationIds?:string[],
	email:string,
	userName?:string,
	firstName:string,
	lastName:string,
	profilePicture?:ImageComponent,
	phoneNumber?:string,
	gender?:AccountGenderEnum,
	birthDate?:DateTime,
	getAge?:number,
	address?:AddressComponent,
	language?:AvailableTranslation,
	settings?:SettingsComponent[],
	securityCheck:boolean,
	organisation:string,
	position:string,
	profileCompleted:boolean
}

export enum AccountTypeEnum {
	admin = "admin",
	user = "user",
	public = "public",
	blogAuthor = "blogAuthor",
	investor = "investor",
	company = "company",
	bank = "bank",
	consultant = "consultant",
	organisationOwner = "organisationOwner"
}

export type AddressComponent = {
	__typename?: "AddressComponent",
	number?:string,
	street?:string,
	streetBis?:string,
	floor?:string,
	box?:string,
	zip?:string,
	state?:string,
	city:string,
	country:string
}

export enum AvailableTranslation {
	en = "en"
}

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

export type EngineFileInitOutput = {
	__typename?: "EngineFileInitOutput",
	uploadUrl:string,
	file:EngineFileSchema
}

export type EngineFileSchema = {
	__typename?: "EngineFileSchema",
	accountId:string,
	mime:string,
	fileName:string,
	fileNameMedium?:string,
	fileNameSmall?:string,
	large?:string,
	medium?:string,
	small?:string,
	account?:AccountModel,
	_id:string,
	organisationId?:string,
	paths?:EnginePathComponent[],
	by?:MetaBy,
	permissions?:MetaPermissions,
	createdAt:DateTime,
	updatedAt:DateTime,
	tagsIds?:string[],
	getTags?:TagSchema[],
	getUrl?:string
}

export type EnginePathComponent = {
	__typename?: "EnginePathComponent",
	ressourceModel:ModelLoadersEnum,
	ressourceId:string
}

export enum FileSize {
	large = "large",
	medium = "medium",
	small = "small"
}

export enum FilesRessourceEnum {
	companiesData = "companiesData"
}

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

export type IEngineSchema = {
	__interface:{
			_id:string,
	organisationId?:string,
	paths?:EnginePathComponent[],
	by?:MetaBy,
	permissions?:MetaPermissions,
	createdAt:DateTime,
	updatedAt:DateTime,
	tagsIds?:string[]
	};
	__resolve:{
		['...on EngineFileSchema']: EngineFileSchema;
		['...on TagSchema']: TagSchema;
	}
}

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

export type MetaBy = {
	__typename?: "MetaBy",
	createdBy?:string,
	updatedBy?:string,
	deletedBy?:string
}

export type MetaPermissions = {
	__typename?: "MetaPermissions",
	r:string[],
	w:string[],
	d:string[]
}

export enum ModelLoadersEnum {
	streams = "streams",
	notifications = "notifications",
	pages = "pages",
	accounts = "accounts",
	companies = "companies",
	naces = "naces",
	companiesData = "companiesData",
	managementInstitutions = "managementInstitutions"
}

export type Mutation = {
	__typename?: "Mutation",
	filesInitUpload:EngineFileInitOutput
}

export type NewFileUploadInitInput = {
		ressourceModel?:FilesRessourceEnum,
	ressourceId?:string,
	fileName:string,
	privateFile?:boolean,
	tagsIds?:string[]
}

export type Query = {
	__typename?: "Query",
	filesGetMine:EngineFileSchema[],
	filesGetMineCount:EngineFileSchema[],
	filesGetSharedWithMe:EngineFileSchema[],
	filesGetSharedWithMeCount:EngineFileSchema[],
	filesGetOne:EngineFileSchema
}

export type SettingsComponent = {
	__typename?: "SettingsComponent",
	type:SettingsTypeEnum,
	email?:boolean,
	pushNotifications?:boolean,
	sms?:boolean
}

export enum SettingsTypeEnum {
	notification = "notification"
}

export type TagSchema = {
	__typename?: "TagSchema",
	title:string,
	_id:string,
	organisationId?:string,
	paths?:EnginePathComponent[],
	by?:MetaBy,
	permissions?:MetaPermissions,
	createdAt:DateTime,
	updatedAt:DateTime,
	tagsIds?:string[]
}

export const AllTypesProps: Record<string,any> = {
	AccountGenderEnum: "enum",
	AccountTypeEnum: "enum",
	AvailableTranslation: "enum",
	DateTime: "String",
	EngineFileSchema:{
		getUrl:{
			size:{
				type:"FileSize",
				array:false,
				arrayRequired:false,
				required:false
			}
		}
	},
	FileSize: "enum",
	FilesRessourceEnum: "enum",
	GetArgs:{
		limit:{
			type:"Int",
			array:false,
			arrayRequired:false,
			required:true
		},
		skip:{
			type:"Int",
			array:false,
			arrayRequired:false,
			required:true
		},
		sort:{
			type:"String",
			array:false,
			arrayRequired:false,
			required:false
		}
	},
	ModelLoadersEnum: "enum",
	Mutation:{
		filesInitUpload:{
			input:{
				type:"NewFileUploadInitInput",
				array:false,
				arrayRequired:false,
				required:true
			}
		}
	},
	NewFileUploadInitInput:{
		ressourceModel:{
			type:"FilesRessourceEnum",
			array:false,
			arrayRequired:false,
			required:false
		},
		ressourceId:{
			type:"String",
			array:false,
			arrayRequired:false,
			required:false
		},
		fileName:{
			type:"String",
			array:false,
			arrayRequired:false,
			required:true
		},
		privateFile:{
			type:"Boolean",
			array:false,
			arrayRequired:false,
			required:false
		},
		tagsIds:{
			type:"String",
			array:true,
			arrayRequired:false,
			required:true
		}
	},
	Query:{
		filesGetMine:{
			pagination:{
				type:"GetArgs",
				array:false,
				arrayRequired:false,
				required:false
			},
			sharedWith:{
				type:"String",
				array:false,
				arrayRequired:false,
				required:false
			},
			tagsIds:{
				type:"String",
				array:true,
				arrayRequired:false,
				required:true
			},
			search:{
				type:"String",
				array:false,
				arrayRequired:false,
				required:false
			}
		},
		filesGetMineCount:{
			pagination:{
				type:"GetArgs",
				array:false,
				arrayRequired:false,
				required:false
			},
			sharedWith:{
				type:"String",
				array:false,
				arrayRequired:false,
				required:false
			},
			tagsIds:{
				type:"String",
				array:true,
				arrayRequired:false,
				required:true
			},
			search:{
				type:"String",
				array:false,
				arrayRequired:false,
				required:false
			}
		},
		filesGetSharedWithMe:{
			pagination:{
				type:"GetArgs",
				array:false,
				arrayRequired:false,
				required:false
			},
			sharedWith:{
				type:"String",
				array:false,
				arrayRequired:false,
				required:false
			},
			tagsIds:{
				type:"String",
				array:true,
				arrayRequired:false,
				required:true
			},
			search:{
				type:"String",
				array:false,
				arrayRequired:false,
				required:false
			}
		},
		filesGetSharedWithMeCount:{
			pagination:{
				type:"GetArgs",
				array:false,
				arrayRequired:false,
				required:false
			},
			sharedWith:{
				type:"String",
				array:false,
				arrayRequired:false,
				required:false
			},
			tagsIds:{
				type:"String",
				array:true,
				arrayRequired:false,
				required:true
			},
			search:{
				type:"String",
				array:false,
				arrayRequired:false,
				required:false
			}
		},
		filesGetOne:{
			id:{
				type:"String",
				array:false,
				arrayRequired:false,
				required:true
			}
		}
	},
	SettingsTypeEnum: "enum"
}

export const ReturnTypes: Record<string,any> = {
	AccountModel:{
		_id:"ID",
		organisationId:"ID",
		createdBy:"ID",
		updatedBy:"ID",
		deletedBy:"ID",
		createdAt:"DateTime",
		updatedAt:"DateTime",
		r:"String",
		w:"String",
		d:"String",
		types:"AccountTypeEnum",
		organisationIds:"String",
		email:"String",
		userName:"String",
		firstName:"String",
		lastName:"String",
		profilePicture:"ImageComponent",
		phoneNumber:"String",
		gender:"AccountGenderEnum",
		birthDate:"DateTime",
		getAge:"Int",
		address:"AddressComponent",
		language:"AvailableTranslation",
		settings:"SettingsComponent",
		securityCheck:"Boolean",
		organisation:"String",
		position:"String",
		profileCompleted:"Boolean"
	},
	AddressComponent:{
		number:"String",
		street:"String",
		streetBis:"String",
		floor:"String",
		box:"String",
		zip:"String",
		state:"String",
		city:"String",
		country:"String"
	},
	EngineFileInitOutput:{
		uploadUrl:"String",
		file:"EngineFileSchema"
	},
	EngineFileSchema:{
		accountId:"String",
		mime:"String",
		fileName:"String",
		fileNameMedium:"String",
		fileNameSmall:"String",
		large:"String",
		medium:"String",
		small:"String",
		account:"AccountModel",
		_id:"ID",
		organisationId:"ID",
		paths:"EnginePathComponent",
		by:"MetaBy",
		permissions:"MetaPermissions",
		createdAt:"DateTime",
		updatedAt:"DateTime",
		tagsIds:"String",
		getTags:"TagSchema",
		getUrl:"String"
	},
	EnginePathComponent:{
		ressourceModel:"ModelLoadersEnum",
		ressourceId:"String"
	},
	IEngineSchema:{
		"...on EngineFileSchema": "EngineFileSchema",
		"...on TagSchema": "TagSchema",
		_id:"ID",
		organisationId:"ID",
		paths:"EnginePathComponent",
		by:"MetaBy",
		permissions:"MetaPermissions",
		createdAt:"DateTime",
		updatedAt:"DateTime",
		tagsIds:"String"
	},
	ImageComponent:{
		title:"String",
		fileType:"String",
		large:"String",
		medium:"String",
		small:"String"
	},
	MetaBy:{
		createdBy:"ID",
		updatedBy:"ID",
		deletedBy:"ID"
	},
	MetaPermissions:{
		r:"String",
		w:"String",
		d:"String"
	},
	Mutation:{
		filesInitUpload:"EngineFileInitOutput"
	},
	Query:{
		filesGetMine:"EngineFileSchema",
		filesGetMineCount:"EngineFileSchema",
		filesGetSharedWithMe:"EngineFileSchema",
		filesGetSharedWithMeCount:"EngineFileSchema",
		filesGetOne:"EngineFileSchema"
	},
	SettingsComponent:{
		type:"SettingsTypeEnum",
		email:"Boolean",
		pushNotifications:"Boolean",
		sms:"Boolean"
	},
	TagSchema:{
		title:"String",
		_id:"ID",
		organisationId:"ID",
		paths:"EnginePathComponent",
		by:"MetaBy",
		permissions:"MetaPermissions",
		createdAt:"DateTime",
		updatedAt:"DateTime",
		tagsIds:"String"
	}
}

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



export type UnwrapPromise<T> = T extends Promise<infer R> ? R : T;
export type ZeusState<T extends (...args: any[]) => Promise<any>> = NonNullable<
  UnwrapPromise<ReturnType<T>>
>;
export type ZeusHook<
  T extends (
    ...args: any[]
  ) => Record<string, (...args: any[]) => Promise<any>>,
  N extends keyof ReturnType<T>
> = ZeusState<ReturnType<T>[N]>;

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 ValuesOf<T> = T[keyof T];

export type MapResolve<SRC, DST> = SRC extends {
    __interface: infer INTERFACE;
    __resolve: Record<string, { __typename?: string }> & infer IMPLEMENTORS;
  }
  ?
  ValuesOf<{
    [k in (keyof SRC['__resolve'] & keyof DST)]: ({
      [rk in (keyof SRC['__resolve'][k] & keyof DST[k])]: LastMapTypeSRCResolver<SRC['__resolve'][k][rk], DST[k][rk]>
    } & {
      __typename: SRC['__resolve'][k]['__typename']
    })
  }>
  :
  never;

export type MapInterface<SRC, DST> = SRC extends {
    __interface: infer INTERFACE;
    __resolve: Record<string, { __typename?: string }> & infer IMPLEMENTORS;
  }
  ?
  (MapResolve<SRC, DST> extends never ? {} : MapResolve<SRC, DST>) & {
  [k in (keyof SRC['__interface'] & keyof DST)]: LastMapTypeSRCResolver<SRC['__interface'][k], DST[k]>
} : 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>;

export 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>) => Promise<any>;



export const ZeusSelect = <T>() => ((t: any) => t) as SelectionFunction<T>;

export const ScalarResolver = (scalar: string, value: any) => {
  switch (scalar) {
    case 'String':
      return  `${JSON.stringify(value)}`;
    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 = resolvedValue.array;
    const isArrayRequired = resolvedValue.arrayRequired;
    if (typeof value === 'string' && value.startsWith(`ZEUS_VAR$`)) {
        const isRequired = resolvedValue.required ? '!' : '';
        let t = `${typeResolved}`;
        if (isArray) {
          if (isRequired) {
              t = `${t}!`;
          }
          t = `[${t}]`;
          if(isArrayRequired){
            t = `${t}!`;
          }
        }else{
          if (isRequired) {
                t = `${t}!`;
          }
        }
        return `\$${value.split(`ZEUS_VAR$`)[1]}__ZEUS_VAR__${t}`;
    }
    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).filter((k) => typeof values[k] !== 'undefined');

  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)
        .filter((k) => typeof a[k] !== 'undefined')
        .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__\[?[^!^\]^\s^,^\)^\}]*[!]?[\]]?[!]?/g;
  let result;
  const AllVariables: string[] = [];
  while ((result = regex.exec(query))) {
    if (AllVariables.includes(result[0])) {
      continue;
    }
    AllVariables.push(result[0]);
  }
  if (!AllVariables.length) {
    return query;
  }
  let filteredQuery = query;
  AllVariables.forEach((variable) => {
    while (filteredQuery.includes(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).then((r:any) => { 
  seekForAliases(r)
  return r
});


const seekForAliases = (response: any) => {
  const traverseAlias = (value: any) => {
    if (Array.isArray(value)) {
      value.forEach(seekForAliases);
    } else {
      if (typeof value === 'object') {
        seekForAliases(value);
      }
    }
  };
  if (typeof response === 'object' && response) {
    const keys = Object.keys(response);
    if (keys.length < 1) {
      return;
    }
    keys.forEach((k) => {
      const value = response[k];
      if (k.indexOf('__alias__') !== -1) {
        const [operation, alias] = k.split('__alias__');
        response[alias] = {
          [operation]: value,
        };
        delete response[k];
      }
      traverseAlias(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((_, 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);
          }
          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);
        }
        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) => (_: any) => o) as CastToGraphQL<
  ValueTypes["Query"],
  Query
>,
mutation: ((o: any) => (_: any) => o) as CastToGraphQL<
  ValueTypes["Mutation"],
  Mutation
>
};
export const Selectors = {
  query: ZeusSelect<ValueTypes["Query"]>(),
mutation: ZeusSelect<ValueTypes["Mutation"]>()
};
  

export const Gql = Chain('https://staging-api.greenomy.io/uploads')