import {
	BINARY_ENCODING,
	IExecuteFunctions,
} from 'n8n-core';

import {
	IDataObject,
	INodeExecutionData,
	INodeType,
	INodeTypeDescription,
	NodeOperationError,
} from 'n8n-workflow';

import {
	googleApiRequest,
	googleApiRequestAllItems,
} from './GenericFunctions';

import { v4 as uuid } from 'uuid';

export class GoogleDrive implements INodeType {
	description: INodeTypeDescription = {
		displayName: 'Google Drive',
		name: 'googleDrive',
		icon: 'file:googleDrive.svg',
		group: ['input'],
		version: 1,
		subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
		description: 'Access data on Google Drive',
		defaults: {
			name: 'Google Drive',
			color: '#4285F4',
		},
		inputs: ['main'],
		outputs: ['main'],
		credentials: [
			{
				name: 'googleApi',
				required: true,
				displayOptions: {
					show: {
						authentication: [
							'serviceAccount',
						],
					},
				},
			},
			{
				name: 'googleDriveOAuth2Api',
				required: true,
				displayOptions: {
					show: {
						authentication: [
							'oAuth2',
						],
					},
				},
			},
		],
		properties: [
			{
				displayName: 'Authentication',
				name: 'authentication',
				type: 'options',
				options: [
					{
						name: 'Service Account',
						value: 'serviceAccount',
					},
					{
						name: 'OAuth2',
						value: 'oAuth2',
					},
				],
				default: 'serviceAccount',
			},
			{
				displayName: 'Resource',
				name: 'resource',
				type: 'options',
				options: [
					{
						name: 'Drive',
						value: 'drive',
					},
					{
						name: 'File',
						value: 'file',
					},
					{
						name: 'Folder',
						value: 'folder',
					},
				],
				default: 'file',
				description: 'The resource to operate on.',
			},


			// ----------------------------------
			//         operations
			// ----------------------------------
			{
				displayName: 'Operation',
				name: 'operation',
				type: 'options',
				displayOptions: {
					show: {
						resource: [
							'file',
						],
					},
				},
				options: [
					{
						name: 'Copy',
						value: 'copy',
						description: 'Copy a file',
					},
					{
						name: 'Delete',
						value: 'delete',
						description: 'Delete a file',
					},
					{
						name: 'Download',
						value: 'download',
						description: 'Download a file',
					},
					{
						name: 'List',
						value: 'list',
						description: 'List files and folders',
					},
					{
						name: 'Share',
						value: 'share',
						description: 'Share a file',
					},
					{
						name: 'Update',
						value: 'update',
						description: 'Update a file',
					},
					{
						name: 'Upload',
						value: 'upload',
						description: 'Upload a file',
					},
				],
				default: 'upload',
				description: 'The operation to perform.',
			},

			{
				displayName: 'Operation',
				name: 'operation',
				type: 'options',
				displayOptions: {
					show: {
						resource: [
							'folder',
						],
					},
				},
				options: [
					{
						name: 'Create',
						value: 'create',
						description: 'Create a folder',
					},
					{
						name: 'Delete',
						value: 'delete',
						description: 'Delete a folder',
					},
					{
						name: 'Share',
						value: 'share',
						description: 'Share a folder',
					},
				],
				default: 'create',
				description: 'The operation to perform.',
			},


			// ----------------------------------
			//         file
			// ----------------------------------

			// ----------------------------------
			//         file:copy
			// ----------------------------------
			{
				displayName: 'ID',
				name: 'fileId',
				type: 'string',
				default: '',
				required: true,
				displayOptions: {
					show: {
						operation: [
							'copy',
						],
						resource: [
							'file',
						],
					},
				},
				description: 'The ID of the file to copy.',
			},

			// ----------------------------------
			//         file/folder:delete
			// ----------------------------------
			{
				displayName: 'ID',
				name: 'fileId',
				type: 'string',
				default: '',
				required: true,
				displayOptions: {
					show: {
						operation: [
							'delete',
						],
						resource: [
							'file',
							'folder',
						],
					},
				},
				description: 'The ID of the file/folder to delete.',
			},


			// ----------------------------------
			//         file:download
			// ----------------------------------
			{
				displayName: 'File Id',
				name: 'fileId',
				type: 'string',
				default: '',
				required: true,
				displayOptions: {
					show: {
						operation: [
							'download',
						],
						resource: [
							'file',
						],
					},
				},
				description: 'The ID of the file to download.',
			},
			{
				displayName: 'Binary Property',
				name: 'binaryPropertyName',
				type: 'string',
				required: true,
				default: 'data',
				displayOptions: {
					show: {
						operation: [
							'download',
						],
						resource: [
							'file',
						],
					},
				},
				description: 'Name of the binary property to which to<br />write the data of the read file.',
			},
			{
				displayName: 'Options',
				name: 'options',
				type: 'collection',
				placeholder: 'Add Option',
				default: {},
				displayOptions: {
					show: {
						operation: [
							'download',
						],
						resource: [
							'file',
						],
					},
				},
				options: [
					{
						displayName: 'File Name',
						name: 'fileName',
						type: 'string',
						default: '',
						description: 'File name. Ex: data.pdf',
					},
				],
			},


			// ----------------------------------
			//         file:list
			// ----------------------------------
			{
				displayName: 'Use Query String',
				name: 'useQueryString',
				type: 'boolean',
				default: false,
				displayOptions: {
					show: {
						operation: [
							'list',
						],
						resource: [
							'file',
						],
					},
				},
				description: 'If a query string should be used to filter results.',
			},
			{
				displayName: 'Query String',
				name: 'queryString',
				type: 'string',
				default: '',
				displayOptions: {
					show: {
						operation: [
							'list',
						],
						useQueryString: [
							true,
						],
						resource: [
							'file',
						],
					},
				},
				placeholder: 'name contains \'invoice\'',
				description: 'Query to use to return only specific files.',
			},
			{
				displayName: 'Limit',
				name: 'limit',
				type: 'number',
				displayOptions: {
					show: {
						operation: [
							'list',
						],
						resource: [
							'file',
						],
					},
				},
				typeOptions: {
					minValue: 1,
					maxValue: 1000,
				},
				default: 100,
				description: 'How many files to return.',
			},
			{
				displayName: 'Filters',
				name: 'queryFilters',
				placeholder: 'Add Filter',
				description: 'Filters to use to return only specific files.',
				type: 'fixedCollection',
				typeOptions: {
					multipleValues: true,
				},
				default: {},
				displayOptions: {
					show: {
						operation: [
							'list',
						],
						useQueryString: [
							false,
						],
						resource: [
							'file',
						],
					},
				},
				options: [
					{
						name: 'name',
						displayName: 'Name',
						values: [
							{
								displayName: 'Operation',
								name: 'operation',
								type: 'options',
								options: [
									{
										name: 'Contains',
										value: 'contains',
									},
									{
										name: 'Is',
										value: 'is',
									},
									{
										name: 'Is Not',
										value: 'isNot',
									},

								],
								default: 'contains',
								description: 'Operation to perform.',
							},
							{
								displayName: 'Value',
								name: 'value',
								type: 'string',
								default: '',
								description: 'The value for operation.',
							},
						],
					},
					{
						name: 'mimeType',
						displayName: 'Mime Type',
						values: [
							{
								displayName: 'Mime Type',
								name: 'mimeType',
								type: 'options',
								options: [

									{
										name: 'Custom Mime Type',
										value: 'custom',
									},
									{
										name: '	3rd party shortcut',
										value: 'application/vnd.google-apps.drive-sdk',
									},
									{
										name: 'Audio',
										value: 'application/vnd.google-apps.audio',
									},
									{
										name: 'Google Apps Scripts',
										value: 'application/vnd.google-apps.script',
									},
									{
										name: 'Google Docs',
										value: 'application/vnd.google-apps.document',
									},
									{
										name: 'Google Drawing',
										value: 'application/vnd.google-apps.drawing',
									},
									{
										name: 'Google Drive file',
										value: 'application/vnd.google-apps.file',
									},
									{
										name: 'Google Drive folder',
										value: 'application/vnd.google-apps.folder',
									},
									{
										name: 'Google Forms',
										value: 'application/vnd.google-apps.form',
									},
									{
										name: 'Google Fusion Tables',
										value: 'application/vnd.google-apps.fusiontable',
									},
									{
										name: 'Google My Maps',
										value: 'application/vnd.google-apps.map',
									},
									{
										name: 'Google Sheets',
										value: 'application/vnd.google-apps.spreadsheet',
									},
									{
										name: 'Google Sites',
										value: 'application/vnd.google-apps.site',
									},
									{
										name: 'Google Slides',
										value: 'application/vnd.google-apps.presentation',
									},
									{
										name: 'Photo',
										value: 'application/vnd.google-apps.photo',
									},
									{
										name: 'Unknown',
										value: 'application/vnd.google-apps.unknown',
									},
									{
										name: 'Video',
										value: 'application/vnd.google-apps.video',
									},

								],
								default: 'application/vnd.google-apps.file',
								description: 'The Mime-Type of the files to return.',
							},
							{
								displayName: 'Custom Mime Type',
								name: 'customMimeType',
								type: 'string',
								default: '',
								displayOptions: {
									show: {
										mimeType: [
											'custom',
										],
									},
								},
								description: 'Custom Mime Type',
							},
						],
					},
				],
			},


			// ----------------------------------
			//         file:share
			// ----------------------------------
			{
				displayName: 'File ID',
				name: 'fileId',
				type: 'string',
				default: '',
				required: true,
				displayOptions: {
					show: {
						operation: [
							'share',
						],
						resource: [
							'file',
							'folder',
						],
					},
				},
				description: 'The ID of the file or shared drive.',
			},
			{
				displayName: 'Permissions',
				name: 'permissionsUi',
				placeholder: 'Add Permission',
				type: 'fixedCollection',
				default: {},
				typeOptions: {
					multipleValues: false,
				},
				displayOptions: {
					show: {
						resource: [
							'file',
							'folder',
						],
						operation: [
							'share',
						],
					},
				},
				options: [
					{
						displayName: 'Permission',
						name: 'permissionsValues',
						values: [
							{
								displayName: 'Role',
								name: 'role',
								type: 'options',
								options: [
									{
										name: 'Owner',
										value: 'owner',
									},
									{
										name: 'Organizer',
										value: 'organizer',
									},
									{
										name: 'File Organizer',
										value: 'fileOrganizer',
									},
									{
										name: 'Writer',
										value: 'writer',
									},
									{
										name: 'Commenter',
										value: 'commenter',
									},
									{
										name: 'Reader',
										value: 'reader',
									},
								],
								default: '',
							},
							{
								displayName: 'Type',
								name: 'type',
								type: 'options',
								options: [
									{
										name: 'User',
										value: 'user',
									},
									{
										name: 'Group',
										value: 'group',
									},
									{
										name: 'Domain',
										value: 'domain',
									},
									{
										name: 'Anyone',
										value: 'anyone',
									},
								],
								default: '',
								description: 'Information about the different types can be found <a href="https://developers.google.com/drive/api/v3/ref-roles">here</a>.',
							},
							{
								displayName: 'Email Address',
								name: 'emailAddress',
								type: 'string',
								displayOptions: {
									show: {
										type: [
											'user',
											'group',
										],
									},
								},
								default: '',
								description: 'The email address of the user or group to which this permission refers',
							},
							{
								displayName: 'Domain',
								name: 'domain',
								type: 'string',
								displayOptions: {
									show: {
										type: [
											'domain',
										],
									},
								},
								default: '',
								description: 'The domain to which this permission refers',
							},
							{
								displayName: 'Allow File Discovery',
								name: 'allowFileDiscovery',
								type: 'boolean',
								displayOptions: {
									show: {
										type: [
											'domain',
											'anyone',
										],
									},
								},
								default: false,
								description: 'Whether the permission allows the file to be discovered through search',
							},
						],
					},
				],
			},

			{
				displayName: 'Binary Data',
				name: 'binaryData',
				type: 'boolean',
				default: false,
				displayOptions: {
					show: {
						operation: [
							'upload',
						],
						resource: [
							'file',
						],
					},
				},
				description: 'If the data to upload should be taken from binary field.',
			},
			{
				displayName: 'File Content',
				name: 'fileContent',
				type: 'string',
				default: '',
				displayOptions: {
					show: {
						operation: [
							'upload',
						],
						resource: [
							'file',
						],
						binaryData: [
							false,
						],
					},

				},
				placeholder: '',
				description: 'The text content of the file to upload.',
			},
			{
				displayName: 'Binary Property',
				name: 'binaryPropertyName',
				type: 'string',
				default: 'data',
				required: true,
				displayOptions: {
					show: {
						operation: [
							'upload',
						],
						resource: [
							'file',
						],
						binaryData: [
							true,
						],
					},

				},
				placeholder: '',
				description: 'Name of the binary property which contains<br />the data for the file to be uploaded.',
			},

			// ----------------------------------
			//         file:update
			// ----------------------------------
			{
				displayName: 'ID',
				name: 'fileId',
				type: 'string',
				default: '',
				required: true,
				displayOptions: {
					show: {
						operation: [
							'update',
						],
						resource: [
							'file',
						],
					},
				},
				description: 'The ID of the file to update.',
			},
			{
				displayName: 'Update Fields',
				name: 'updateFields',
				type: 'collection',
				placeholder: 'Add Option',
				default: {},
				displayOptions: {
					show: {
						operation: [
							'update',
						],
						resource: [
							'file',
						],
					},
				},
				options: [
					{
						displayName: 'File Name',
						name: 'fileName',
						type: 'string',
						default: '',
						description: `The name of the file`,
					},
					{
						displayName: 'Keep Revision Forever',
						name: 'keepRevisionForever',
						type: 'boolean',
						default: false,
						description: `Whether to set the 'keepForever' field in the new head revision.</br>
						his is only applicable to files with binary content in Google Drive.</br>
						Only 200 revisions for the file can be kept forever. If the limit is reached, try deleting pinned revisions.`,
					},
					{
						displayName: 'OCR Language',
						name: 'ocrLanguage',
						type: 'string',
						default: '',
						description: `A language hint for OCR processing during image import (ISO 639-1 code).`,
					},
					{
						displayName: 'Parent ID',
						name: 'parentId',
						type: 'string',
						default: '',
						description: `The ID of the parent to set.`,
					},
					{
						displayName: 'Use Content As Indexable Text',
						name: 'useContentAsIndexableText',
						type: 'boolean',
						default: false,
						description: `Whether to use the uploaded content as indexable text.`,
					},
				],
			},
			{
				displayName: 'Options',
				name: 'options',
				type: 'collection',
				placeholder: 'Add Option',
				default: {},
				displayOptions: {
					show: {
						operation: [
							'update',
						],
						resource: [
							'file',
						],
					},
				},
				options: [
					{
						displayName: 'Fields',
						name: 'fields',
						type: 'multiOptions',
						options: [
							{
								name: '*',
								value: '*',
								description: 'All fields.',
							},
							{
								name: 'explicitlyTrashed',
								value: 'explicitlyTrashed',
							},
							{
								name: 'exportLinks',
								value: 'exportLinks',
							},
							{
								name: 'iconLink',
								value: 'iconLink',
							},
							{
								name: 'hasThumbnail',
								value: 'hasThumbnail',
							},
							{
								name: 'id',
								value: 'id',
							},
							{
								name: 'kind',
								value: 'kind',
							},
							{
								name: 'name',
								value: 'name',
							},
							{
								name: 'mimeType',
								value: 'mimeType',
							},
							{
								name: 'permissions',
								value: 'permissions',
							},
							{
								name: 'shared',
								value: 'shared',
							},
							{
								name: 'spaces',
								value: 'spaces',
							},
							{
								name: 'starred',
								value: 'starred',
							},
							{
								name: 'thumbnailLink',
								value: 'thumbnailLink',
							},
							{
								name: 'trashed',
								value: 'trashed',
							},
							{
								name: 'version',
								value: 'version',
							},
							{
								name: 'webViewLink',
								value: 'webViewLink',
							},
						],
						required: true,
						default: [],
						description: 'The fields to return.',
					},
				],
			},
			// ----------------------------------
			//         file:upload
			// ----------------------------------
			{
				displayName: 'File Name',
				name: 'name',
				type: 'string',
				default: '',
				required: true,
				displayOptions: {
					show: {
						operation: [
							'upload',
						],
						resource: [
							'file',
						],
					},
				},
				placeholder: 'invoice_1.pdf',
				description: 'The name the file should be saved as.',
			},
			// ----------------------------------
			{
				displayName: 'Resolve Data',
				name: 'resolveData',
				type: 'boolean',
				default: false,
				displayOptions: {
					show: {
						operation: [
							'upload',
						],
						resource: [
							'file',
						],
					},
				},
				description: 'By default the response only contain the ID of the file.<br />If this option gets activated it will resolve the data automatically.',
			},
			{
				displayName: 'Parents',
				name: 'parents',
				type: 'string',
				typeOptions: {
					multipleValues: true,
				},
				default: [],
				displayOptions: {
					show: {
						operation: [
							'upload',
						],
						resource: [
							'file',
						],
					},
				},
				description: 'The IDs of the parent folders which contain the file.',
			},

			// ----------------------------------
			//         folder
			// ----------------------------------

			// ----------------------------------
			//         folder:create
			// ----------------------------------
			{
				displayName: 'Folder',
				name: 'name',
				type: 'string',
				default: '',
				required: true,
				displayOptions: {
					show: {
						operation: [
							'create',
						],
						resource: [
							'folder',
						],
					},
				},
				placeholder: 'invoices',
				description: 'The name of folder to create.',
			},
			{
				displayName: 'Options',
				name: 'options',
				type: 'collection',
				placeholder: 'Add Option',
				default: {},
				displayOptions: {
					show: {
						'/operation': [
							'copy',
							'list',
							'share',
							'create',
						],
						'/resource': [
							'file',
							'folder',
						],
					},
				},
				options: [
					{
						displayName: 'Email Message',
						name: 'emailMessage',
						type: 'string',
						displayOptions: {
							show: {
								'/operation': [
									'share',
								],
								'/resource': [
									'file',
									'folder',
								],
							},
						},
						default: '',
						description: 'A plain text custom message to include in the notification email.',
					},
					{
						displayName: 'Enforce Single Parent',
						name: 'enforceSingleParent',
						type: 'boolean',
						displayOptions: {
							show: {
								'/operation': [
									'share',
								],
								'/resource': [
									'file',
									'folder',
								],
							},
						},
						default: false,
						description: `Set to true to opt in to API behavior that aims for all items to have exactly one parent<br>
						This parameter only takes effect if the item is not in a shared drive`,
					},
					{
						displayName: 'Fields',
						name: 'fields',
						type: 'multiOptions',
						displayOptions: {
							show: {
								'/operation': [
									'list',
									'copy',
								],
							},
						},
						options: [
							{
								name: '*',
								value: '*',
								description: 'All fields.',
							},
							{
								name: 'explicitlyTrashed',
								value: 'explicitlyTrashed',
							},
							{
								name: 'exportLinks',
								value: 'exportLinks',
							},
							{
								name: 'iconLink',
								value: 'iconLink',
							},
							{
								name: 'hasThumbnail',
								value: 'hasThumbnail',
							},
							{
								name: 'id',
								value: 'id',
							},
							{
								name: 'kind',
								value: 'kind',
							},
							{
								name: 'name',
								value: 'name',
							},
							{
								name: 'mimeType',
								value: 'mimeType',
							},
							{
								name: 'permissions',
								value: 'permissions',
							},
							{
								name: 'shared',
								value: 'shared',
							},
							{
								name: 'spaces',
								value: 'spaces',
							},
							{
								name: 'starred',
								value: 'starred',
							},
							{
								name: 'thumbnailLink',
								value: 'thumbnailLink',
							},
							{
								name: 'trashed',
								value: 'trashed',
							},
							{
								name: 'version',
								value: 'version',
							},
							{
								name: 'webViewLink',
								value: 'webViewLink',
							},
						],
						required: true,
						default: [],
						description: 'The fields to return.',
					},
					{
						displayName: 'Move To New Owners Root',
						name: 'moveToNewOwnersRoot',
						type: 'boolean',
						displayOptions: {
							show: {
								'/operation': [
									'share',
								],
								'/resource': [
									'file',
									'folder',
								],
							},
						},
						default: '',
						description: `This parameter only takes effect if the item is not in a shared drive and the request is attempting to transfer the ownership of the item.<br>
						When set to true, the item is moved to the new owner's My Drive root folder and all prior parents removed`,
					},
					{
						displayName: 'Send Notification Email',
						name: 'sendNotificationEmail',
						type: 'boolean',
						displayOptions: {
							show: {
								'/operation': [
									'share',
								],
								'/resource': [
									'file',
									'folder',
								],
							},
						},
						default: false,
						description: 'Whether to send a notification email when sharing to users or groups',
					},
					{
						displayName: 'Supports All Drives',
						name: 'supportsAllDrives',
						type: 'boolean',
						displayOptions: {
							show: {
								'/operation': [
									'share',
								],
								'/resource': [
									'file',
									'folder',
								],
							},
						},
						default: false,
						description: 'Whether the requesting application supports both My Drives and shared drives',
					},
					{
						displayName: 'Transfer Ownership',
						name: 'transferOwnership',
						type: 'boolean',
						displayOptions: {
							show: {
								'/operation': [
									'share',
								],
								'/resource': [
									'file',
									'folder',
								],
							},
						},
						default: false,
						description: 'Whether to transfer ownership to the specified user and downgrade the current owner to a writer.',
					},
					{
						displayName: 'Use Domain Admin Access',
						name: 'useDomainAdminAccess',
						type: 'boolean',
						displayOptions: {
							show: {
								'/operation': [
									'share',
								],
								'/resource': [
									'file',
									'folder',
								],
							},
						},
						default: false,
						description: `Perform the operation as domain administrator, i.e. if you are an administrator of the domain to which the shared drive belongs, you will be granted access automatically`,
					},

					{
						displayName: 'File Name',
						name: 'name',
						type: 'string',
						displayOptions: {
							show: {
								'/operation': [
									'copy',
								],
								'/resource': [
									'file',
								],
							},
						},
						default: '',
						placeholder: 'invoice_1.pdf',
						description: 'The name the file should be saved as.',
					},
					{
						displayName: 'Parents',
						name: 'parents',
						type: 'string',
						displayOptions: {
							show: {
								'/operation': [
									'copy',
									'create',
								],
								'/resource': [
									'file',
									'folder',
								],
							},
						},
						typeOptions: {
							multipleValues: true,
						},
						default: [],
						description: 'The IDs of the parent folders the file/folder should be saved in.',
					},
					{
						displayName: 'Spaces',
						name: 'spaces',
						type: 'multiOptions',
						displayOptions: {
							show: {
								'/operation': [
									'list',
								],
								'/resource': [
									'file',
								],
							},
						},
						options: [
							{
								name: '*',
								value: '*',
								description: 'All spaces.',
							},
							{
								name: 'appDataFolder',
								value: 'appDataFolder',
							},
							{
								name: 'drive',
								value: 'drive',
							},
							{
								name: 'photos',
								value: 'photos',
							},
						],
						required: true,
						default: [],
						description: 'The spaces to operate on.',
					},
					{
						displayName: 'Corpora',
						name: 'corpora',
						type: 'options',
						displayOptions: {
							show: {
								'/operation': [
									'list',
								],
								'/resource': [
									'file',
								],
							},
						},
						options: [
							{
								name: 'user',
								value: 'user',
								description: 'All files in "My Drive" and "Shared with me"',
							},
							{
								name: 'domain',
								value: 'domain',
								description: 'All files shared to the user\'s domain that are searchable',
							},
							{
								name: 'drive',
								value: 'drive',
								description: 'All files contained in a single shared drive',
							},
							{
								name: 'allDrives',
								value: 'allDrives',
								description: 'All drives',
							},
						],
						required: true,
						default: '',
						description: 'The corpora to operate on.',
					},
					{
						displayName: 'Drive ID',
						name: 'driveId',
						type: 'string',
						default: '',
						required: false,
						displayOptions: {
							show: {
								'/operation': [
									'list',
								],
								'/resource': [
									'file',
								],
								corpora: [
									'drive',
								],
							},
						},
						description: 'ID of the shared drive to search. The driveId parameter must be specified if and only if corpora is set to drive.',
					},
				],
			},
			// ----------------------------------
			//         drive
			// ----------------------------------
			{
				displayName: 'Operation',
				name: 'operation',
				type: 'options',
				displayOptions: {
					show: {
						resource: [
							'drive',
						],
					},
				},
				options: [
					{
						name: 'Create',
						value: 'create',
						description: 'Create a drive',
					},
					{
						name: 'Delete',
						value: 'delete',
						description: 'Delete a drive',
					},
					{
						name: 'Get',
						value: 'get',
						description: 'Get a drive',
					},
					{
						name: 'List',
						value: 'list',
						description: 'List all drives',
					},
					{
						name: 'Update',
						value: 'update',
						description: 'Update a drive',
					},
				],
				default: 'create',
				description: 'The operation to perform.',
			},
			// ----------------------------------
			//         drive:create
			// ----------------------------------
			{
				displayName: 'Name',
				name: 'name',
				type: 'string',
				default: '',
				required: false,
				displayOptions: {
					show: {
						operation: [
							'create',
						],
						resource: [
							'drive',
						],
					},
				},
				description: 'The name of this shared drive.',
			},
			{
				displayName: 'Options',
				name: 'options',
				type: 'collection',
				placeholder: 'Add Option',
				default: {},
				displayOptions: {
					show: {
						operation: [
							'create',
						],
						resource: [
							'drive',
						],
					},
				},
				options: [
					{
						displayName: 'Capabilities',
						name: 'capabilities',
						type: 'collection',
						placeholder: 'Add Field',
						default: {},
						options: [
							{
								displayName: 'Can Add Children',
								name: 'canAddChildren',
								type: 'boolean',
								default: false,
								description: `Whether the current user can add children to folders in this shared drive.`,
							},
							{
								displayName: 'Can Change Copy Requires Writer Permission Restriction',
								name: 'canChangeCopyRequiresWriterPermissionRestriction',
								type: 'boolean',
								default: false,
								description: `Whether the current user can change the copyRequiresWriterPermission restriction of this shared drive.`,
							},
							{
								displayName: 'Can Change Domain Users Only Restriction',
								name: 'canChangeDomainUsersOnlyRestriction',
								type: 'boolean',
								default: false,
								description: `Whether the current user can change the domainUsersOnly restriction of this shared drive.`,
							},
							{
								displayName: 'Can Change Drive Background',
								name: 'canChangeDriveBackground',
								type: 'boolean',
								default: false,
								description: `Whether the current user can change the background of this shared drive.`,
							},
							{
								displayName: 'Can Change Drive Members Only Restriction',
								name: 'canChangeDriveMembersOnlyRestriction',
								type: 'boolean',
								default: false,
								description: `Whether the current user can change the driveMembersOnly restriction of this shared drive.`,
							},
							{
								displayName: 'Can Comment',
								name: 'canComment',
								type: 'boolean',
								default: false,
								description: `Whether the current user can comment on files in this shared drive.`,
							},
							{
								displayName: 'Can Copy',
								name: 'canCopy',
								type: 'boolean',
								default: false,
								description: `Whether the current user can copy files in this shared drive.`,
							},
							{
								displayName: 'Can Delete Children',
								name: 'canDeleteChildren',
								type: 'boolean',
								default: false,
								description: `Whether the current user can delete children from folders in this shared drive.`,
							},
							{
								displayName: 'Can Delete Drive',
								name: 'canDeleteDrive',
								type: 'boolean',
								default: false,
								description: `Whether the current user can delete this shared drive. Attempting to delete the shared drive may still fail if there are untrashed items inside the shared drive.`,
							},
							{
								displayName: 'Can Download',
								name: 'canDownload',
								type: 'boolean',
								default: false,
								description: `Whether the current user can download files in this shared drive.`,
							},
							{
								displayName: 'Can Edit',
								name: 'canEdit',
								type: 'boolean',
								default: false,
								description: `Whether the current user can edit files in this shared drive`,
							},
							{
								displayName: 'Can List Children',
								name: 'canListChildren',
								type: 'boolean',
								default: false,
								description: `Whether the current user can list the children of folders in this shared drive.`,
							},
							{
								displayName: 'Can Manage Members',
								name: 'canManageMembers',
								type: 'boolean',
								default: false,
								description: `Whether the current user can add members to this shared drive or remove them or change their role.`,
							},
							{
								displayName: 'Can Read Revisions',
								name: 'canReadRevisions',
								type: 'boolean',
								default: false,
								description: `Whether the current user can read the revisions resource of files in this shared drive.`,
							},
							{
								displayName: 'Can Rename',
								name: 'canRename',
								type: 'boolean',
								default: false,
								description: `Whether the current user can rename files or folders in this shared drive.`,
							},
							{
								displayName: 'Can Rename Drive',
								name: 'canRenameDrive',
								type: 'boolean',
								default: false,
								description: `Whether the current user can rename this shared drive.`,
							},
							{
								displayName: 'Can Share',
								name: 'canShare',
								type: 'boolean',
								default: false,
								description: `Whether the current user can rename this shared drive.`,
							},
							{
								displayName: 'Can Trash Children',
								name: 'canTrashChildren',
								type: 'boolean',
								default: false,
								description: `Whether the current user can trash children from folders in this shared drive.`,
							},
						],
					},
					{
						displayName: 'Color RGB',
						name: 'colorRgb',
						type: 'color',
						default: '',
						description: 'The color of this shared drive as an RGB hex string',
					},
					{
						displayName: 'Created Time',
						name: 'createdTime',
						type: 'dateTime',
						default: '',
						description: 'The time at which the shared drive was created (RFC 3339 date-time).',
					},
					{
						displayName: 'Hidden',
						name: 'hidden',
						type: 'boolean',
						default: false,
						description: 'Whether the shared drive is hidden from default view.',
					},
					{
						displayName: 'Restrictions',
						name: 'restrictions',
						type: 'collection',
						placeholder: 'Add Field',
						default: {},
						options: [
							{
								displayName: 'Admin Managed Restrictions',
								name: 'adminManagedRestrictions',
								type: 'boolean',
								default: false,
								description: `Whether the options to copy, print, or download files inside this shared drive,<br/>
								should be disabled for readers and commenters. When this restriction is set to true, it will<br/>
								override the similarly named field to true for any file inside this shared drive.`,
							},
							{
								displayName: 'Copy Requires Writer Permission',
								name: 'copyRequiresWriterPermission',
								type: 'boolean',
								default: false,
								description: `Whether the options to copy, print, or download files inside this shared drive,<br/>
								should be disabled for readers and commenters. When this restriction is set to true, it will<br/>
								override the similarly named field to true for any file inside this shared drive.`,
							},
							{
								displayName: 'Domain Users Only',
								name: 'domainUsersOnly',
								type: 'boolean',
								default: false,
								description: `Whether access to this shared drive and items inside this shared drive<br/>
								is restricted to users of the domain to which this shared drive belongs. This restriction<br/>
								may be overridden by other sharing policies controlled outside of this shared drive.`,
							},
							{
								displayName: 'Drive Members Only',
								name: 'driveMembersOnly',
								type: 'boolean',
								default: false,
								description: `Whether access to items inside this shared drive is restricted to its members.`,
							},
						],
					},
				],
			},
			// ----------------------------------
			//         drive:delete
			// ----------------------------------
			{
				displayName: 'Drive ID',
				name: 'driveId',
				type: 'string',
				default: '',
				required: false,
				displayOptions: {
					show: {
						operation: [
							'delete',
						],
						resource: [
							'drive',
						],
					},
				},
				description: 'The ID of the shared drive.',
			},
			// ----------------------------------
			//         drive:get
			// ----------------------------------
			{
				displayName: 'Drive ID',
				name: 'driveId',
				type: 'string',
				default: '',
				required: false,
				displayOptions: {
					show: {
						operation: [
							'get',
						],
						resource: [
							'drive',
						],
					},
				},
				description: 'The ID of the shared drive.',
			},
			{
				displayName: 'Options',
				name: 'options',
				type: 'collection',
				placeholder: 'Add Option',
				default: {},
				displayOptions: {
					show: {
						operation: [
							'get',
						],
						resource: [
							'drive',
						],
					},
				},
				options: [
					{
						displayName: 'Use Domain Admin Access',
						name: 'useDomainAdminAccess',
						type: 'boolean',
						default: false,
						description: 'Issue the request as a domain administrator; if set to true, then the requester will be granted access if they are an administrator of the domain to which the shared drive belongs. (Default: false)',
					},
				],
			},
			// ----------------------------------
			//         drive:list
			// ----------------------------------
			{
				displayName: 'Return All',
				name: 'returnAll',
				type: 'boolean',
				displayOptions: {
					show: {
						operation: [
							'list',
						],
						resource: [
							'drive',
						],
					},
				},
				default: false,
				description: 'If all results should be returned or only up to a given limit.',
			},
			{
				displayName: 'Limit',
				name: 'limit',
				type: 'number',
				displayOptions: {
					show: {
						operation: [
							'list',
						],
						resource: [
							'drive',
						],
						returnAll: [
							false,
						],
					},
				},
				typeOptions: {
					minValue: 1,
					maxValue: 200,
				},
				default: 100,
				description: 'How many results to return.',
			},
			{
				displayName: 'Options',
				name: 'options',
				type: 'collection',
				placeholder: 'Add Option',
				default: {},
				displayOptions: {
					show: {
						operation: [
							'list',
						],
						resource: [
							'drive',
						],
					},
				},
				options: [
					{
						displayName: 'Query',
						name: 'q',
						type: 'string',
						default: '',
						description: 'Query string for searching shared drives. See the <a href="https://developers.google.com/drive/api/v3/search-shareddrives">"Search for shared drives"</a> guide for supported syntax.',
					},
					{
						displayName: 'Use Domain Admin Access',
						name: 'useDomainAdminAccess',
						type: 'boolean',
						default: false,
						description: 'Issue the request as a domain administrator; if set to true, then the requester will be granted access if they are an administrator of the domain to which the shared drive belongs. (Default: false)',
					},
				],
			},
			// ----------------------------------
			//         drive:update
			// ----------------------------------
			{
				displayName: 'Drive ID',
				name: 'driveId',
				type: 'string',
				default: '',
				required: false,
				displayOptions: {
					show: {
						operation: [
							'update',
						],
						resource: [
							'drive',
						],
					},
				},
				description: 'The ID of the shared drive.',
			},
			{
				displayName: 'Update Fields',
				name: 'options',
				type: 'collection',
				placeholder: 'Add Option',
				default: {},
				displayOptions: {
					show: {
						operation: [
							'update',
						],
						resource: [
							'drive',
						],
					},
				},
				options: [
					{
						displayName: 'Color RGB',
						name: 'colorRgb',
						type: 'color',
						default: '',
						description: 'The color of this shared drive as an RGB hex string',
					},
					{
						displayName: 'Name',
						name: 'name',
						type: 'string',
						default: '',
						description: 'The name of this shared drive.',
					},
					{
						displayName: 'Restrictions',
						name: 'restrictions',
						type: 'collection',
						placeholder: 'Add Field',
						default: {},
						options: [
							{
								displayName: 'Admin Managed Restrictions',
								name: 'adminManagedRestrictions',
								type: 'boolean',
								default: false,
								description: `Whether the options to copy, print, or download files inside this shared drive,<br/>
								should be disabled for readers and commenters. When this restriction is set to true, it will<br/>
								override the similarly named field to true for any file inside this shared drive.`,
							},
							{
								displayName: 'Copy Requires Writer Permission',
								name: 'copyRequiresWriterPermission',
								type: 'boolean',
								default: false,
								description: `Whether the options to copy, print, or download files inside this shared drive,<br/>
								should be disabled for readers and commenters. When this restriction is set to true, it will<br/>
								override the similarly named field to true for any file inside this shared drive.`,
							},
							{
								displayName: 'Domain Users Only',
								name: 'domainUsersOnly',
								type: 'boolean',
								default: false,
								description: `Whether access to this shared drive and items inside this shared drive<br/>
								is restricted to users of the domain to which this shared drive belongs. This restriction<br/>
								may be overridden by other sharing policies controlled outside of this shared drive.`,
							},
							{
								displayName: 'Drive Members Only',
								name: 'driveMembersOnly',
								type: 'boolean',
								default: false,
								description: `Whether access to items inside this shared drive is restricted to its members.`,
							},
						],
					},
				],
			},
			{
				displayName: 'Options',
				name: 'options',
				type: 'collection',
				placeholder: 'Add Option',
				default: {},
				displayOptions: {
					show: {
						operation: [
							'upload',
						],
						resource: [
							'file',
						],
					},
				},
				options: [
					{
						displayName: 'APP Properties',
						name: 'appPropertiesUi',
						placeholder: 'Add Property',
						type: 'fixedCollection',
						default: '',
						typeOptions: {
							multipleValues: true,
						},
						description: 'A collection of arbitrary key-value pairs which are private to the requesting app',
						options: [
							{
								name: 'appPropertyValues',
								displayName: 'APP Property',
								values: [
									{
										displayName: 'Key',
										name: 'key',
										type: 'string',
										default: '',
										description: 'Name of the key to add.',
									},
									{
										displayName: 'Value',
										name: 'value',
										type: 'string',
										default: '',
										description: 'Value to set for the key.',
									},
								],
							},
						],
					},
					{
						displayName: 'Properties',
						name: 'propertiesUi',
						placeholder: 'Add Property',
						type: 'fixedCollection',
						default: '',
						typeOptions: {
							multipleValues: true,
						},
						description: 'A collection of arbitrary key-value pairs which are visible to all apps.',
						options: [
							{
								name: 'propertyValues',
								displayName: 'Property',
								values: [
									{
										displayName: 'Key',
										name: 'key',
										type: 'string',
										default: '',
										description: 'Name of the key to add.',
									},
									{
										displayName: 'Value',
										name: 'value',
										type: 'string',
										default: '',
										description: 'Value to set for the key.',
									},
								],
							},
						],
					},
				],
			},
		],
	};


	async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
		const items = this.getInputData();
		const returnData: IDataObject[] = [];

		const resource = this.getNodeParameter('resource', 0) as string;
		const operation = this.getNodeParameter('operation', 0) as string;

		for (let i = 0; i < items.length; i++) {
			try {
				const options = this.getNodeParameter('options', i, {}) as IDataObject;

				let queryFields = 'id, name';
				if (options && options.fields) {
					const fields = options.fields as string[];
					if (fields.includes('*')) {
						queryFields = '*';
					} else {
						queryFields = fields.join(', ');
					}
				}

				if (resource === 'drive') {
					if (operation === 'create') {
						// ----------------------------------
						//         create
						// ----------------------------------

						const name = this.getNodeParameter('name', i) as string;

						const body: IDataObject = {
							name,
						};

						Object.assign(body, options);

						const response = await googleApiRequest.call(this, 'POST', `/drive/v3/drives`, body, { requestId: uuid() });

						returnData.push(response as IDataObject);
					}
					if (operation === 'delete') {
						// ----------------------------------
						//         delete
						// ----------------------------------

						const driveId = this.getNodeParameter('driveId', i) as string;

						await googleApiRequest.call(this, 'DELETE', `/drive/v3/drives/${driveId}`);

						returnData.push({ success: true });
					}
					if (operation === 'get') {
						// ----------------------------------
						//         get
						// ----------------------------------

						const driveId = this.getNodeParameter('driveId', i) as string;

						const qs: IDataObject = {};

						Object.assign(qs, options);

						const response = await googleApiRequest.call(this, 'GET', `/drive/v3/drives/${driveId}`, {}, qs);

						returnData.push(response as IDataObject);
					}
					if (operation === 'list') {
						// ----------------------------------
						//         list
						// ----------------------------------
						const returnAll = this.getNodeParameter('returnAll', i) as boolean;

						const qs: IDataObject = {};

						let response: IDataObject[] = [];

						Object.assign(qs, options);

						if (returnAll === true) {
							response = await googleApiRequestAllItems.call(this, 'drives', 'GET', `/drive/v3/drives`, {}, qs);
						} else {
							qs.pageSize = this.getNodeParameter('limit', i) as number;
							const data = await googleApiRequest.call(this, 'GET', `/drive/v3/drives`, {}, qs);
							response = data.drives as IDataObject[];
						}

						returnData.push.apply(returnData, response);
					}
					if (operation === 'update') {
						// ----------------------------------
						//         update
						// ----------------------------------

						const driveId = this.getNodeParameter('driveId', i) as string;

						const body: IDataObject = {};

						Object.assign(body, options);

						const response = await googleApiRequest.call(this, 'PATCH', `/drive/v3/drives/${driveId}`, body);

						returnData.push(response as IDataObject);
					}

				}
				if (resource === 'file') {
					if (operation === 'copy') {
						// ----------------------------------
						//         copy
						// ----------------------------------

						const fileId = this.getNodeParameter('fileId', i) as string;

						const body: IDataObject = {
							fields: queryFields,
						};

						const optionProperties = ['name', 'parents'];
						for (const propertyName of optionProperties) {
							if (options[propertyName] !== undefined) {
								body[propertyName] = options[propertyName];
							}
						}

						const qs = {
							supportsAllDrives: true,
						};

						const response = await googleApiRequest.call(this, 'POST', `/drive/v3/files/${fileId}/copy`, body, qs);

						returnData.push(response as IDataObject);

					} else if (operation === 'download') {
						// ----------------------------------
						//         download
						// ----------------------------------

						const fileId = this.getNodeParameter('fileId', i) as string;
						const options = this.getNodeParameter('options', i) as IDataObject;

						const requestOptions = {
							resolveWithFullResponse: true,
							encoding: null,
							json: false,
						};

						const response = await googleApiRequest.call(this, 'GET', `/drive/v3/files/${fileId}`, {}, { alt: 'media' }, undefined, requestOptions);

						let mimeType: string | undefined;
						let fileName: string | undefined = undefined;
						if (response.headers['content-type']) {
							mimeType = response.headers['content-type'];
						}

						if (options.fileName) {
							fileName = options.fileName as string;
						}

						const newItem: INodeExecutionData = {
							json: items[i].json,
							binary: {},
						};

						if (items[i].binary !== undefined) {
							// Create a shallow copy of the binary data so that the old
							// data references which do not get changed still stay behind
							// but the incoming data does not get changed.
							Object.assign(newItem.binary, items[i].binary);
						}

						items[i] = newItem;

						const dataPropertyNameDownload = this.getNodeParameter('binaryPropertyName', i) as string;

						const data = Buffer.from(response.body as string);

						items[i].binary![dataPropertyNameDownload] = await this.helpers.prepareBinaryData(data as unknown as Buffer, fileName, mimeType);

					} else if (operation === 'list') {
						// ----------------------------------
						//         list
						// ----------------------------------

						let querySpaces = '';
						if (options.spaces) {
							const spaces = options.spaces as string[];
							if (spaces.includes('*')) {
								querySpaces = 'appDataFolder, drive, photos';
							} else {
								querySpaces = spaces.join(', ');
							}
						}

						let queryCorpora = '';
						if (options.corpora) {
							queryCorpora = options.corpora as string;
						}

						let driveId: string | undefined;
						driveId = options.driveId as string;
						if (driveId === '') {
							driveId = undefined;
						}

						let queryString = '';
						const useQueryString = this.getNodeParameter('useQueryString', i) as boolean;
						if (useQueryString === true) {
							// Use the user defined query string
							queryString = this.getNodeParameter('queryString', i) as string;
						} else {
							// Build query string out of parameters set by user
							const queryFilters = this.getNodeParameter('queryFilters', i) as IDataObject;

							const queryFilterFields: string[] = [];
							if (queryFilters.name) {
								(queryFilters.name as IDataObject[]).forEach(nameFilter => {
									let operation = nameFilter.operation;
									if (operation === 'is') {
										operation = '=';
									} else if (operation === 'isNot') {
										operation = '!=';
									}
									queryFilterFields.push(`name ${operation} '${nameFilter.value}'`);
								});

								queryString += queryFilterFields.join(' or ');
							}

							queryFilterFields.length = 0;
							if (queryFilters.mimeType) {
								(queryFilters.mimeType as IDataObject[]).forEach(mimeTypeFilter => {
									let mimeType = mimeTypeFilter.mimeType;
									if (mimeTypeFilter.mimeType === 'custom') {
										mimeType = mimeTypeFilter.customMimeType;
									}
									queryFilterFields.push(`mimeType = '${mimeType}'`);
								});

								if (queryFilterFields.length) {
									if (queryString !== '') {
										queryString += ' and ';
									}

									queryString += queryFilterFields.join(' or ');
								}
							}
						}

						const pageSize = this.getNodeParameter('limit', i) as number;

						const qs = {
							pageSize,
							orderBy: 'modifiedTime',
							fields: `nextPageToken, files(${queryFields})`,
							spaces: querySpaces,
							q: queryString,
							includeItemsFromAllDrives: (queryCorpora !== '' || driveId !== ''),
							supportsAllDrives: (queryCorpora !== '' || driveId !== ''),
						};

						const response = await googleApiRequest.call(this, 'GET', `/drive/v3/files`, {}, qs);

						const files = response!.files;

						return [this.helpers.returnJsonArray(files as IDataObject[])];

					} else if (operation === 'upload') {
						// ----------------------------------
						//         upload
						// ----------------------------------
						const resolveData = this.getNodeParameter('resolveData', 0) as boolean;

						let mimeType = 'text/plain';
						let body;
						let originalFilename: string | undefined;
						if (this.getNodeParameter('binaryData', i) === true) {
							// Is binary file to upload
							const item = items[i];

							if (item.binary === undefined) {
								throw new NodeOperationError(this.getNode(), 'No binary data exists on item!');
							}

							const propertyNameUpload = this.getNodeParameter('binaryPropertyName', i) as string;

							if (item.binary[propertyNameUpload] === undefined) {
								throw new NodeOperationError(this.getNode(), `No binary data property "${propertyNameUpload}" does not exists on item!`);
							}

							if (item.binary[propertyNameUpload].mimeType) {
								mimeType = item.binary[propertyNameUpload].mimeType;
							}

							if (item.binary[propertyNameUpload].fileName) {
								originalFilename = item.binary[propertyNameUpload].fileName;
							}

							body = Buffer.from(item.binary[propertyNameUpload].data, BINARY_ENCODING);
						} else {
							// Is text file
							body = Buffer.from(this.getNodeParameter('fileContent', i) as string, 'utf8');
						}

						const name = this.getNodeParameter('name', i) as string;
						const parents = this.getNodeParameter('parents', i) as string[];

						let qs: IDataObject = {
							fields: queryFields,
							uploadType: 'media',
						};

						const requestOptions = {
							headers: {
								'Content-Type': mimeType,
								'Content-Length': body.byteLength,
							},
							encoding: null,
							json: false,
						};

						let response = await googleApiRequest.call(this, 'POST', `/upload/drive/v3/files`, body, qs, undefined, requestOptions);

						body = {
							mimeType,
							name,
							originalFilename,
						};

						const properties = this.getNodeParameter('options.propertiesUi.propertyValues', i, []) as IDataObject[];

						if (properties.length) {
							Object.assign(body, { properties: properties.reduce((obj, value) => Object.assign(obj, { [`${value.key}`]: value.value }), {}) } );
						}

						const appProperties = this.getNodeParameter('options.appPropertiesUi.appPropertyValues', i, []) as IDataObject[];

						if (properties.length) {
							Object.assign(body, { appProperties: appProperties.reduce((obj, value) => Object.assign(obj, { [`${value.key}`]: value.value }), {}) });
						}

						qs = {
							addParents: parents.join(','),
							// When set to true shared drives can be used.
							supportsAllDrives: true,
						};

						response = await googleApiRequest.call(this, 'PATCH', `/drive/v3/files/${JSON.parse(response).id}`, body, qs);

						if (resolveData === true) {
							response = await googleApiRequest.call(this, 'GET', `/drive/v3/files/${response.id}`, {}, { fields: '*' });
						}

						returnData.push(response as IDataObject);
					} else if (operation === 'update') {
						// ----------------------------------
						//         file:update
						// ----------------------------------

						const id = this.getNodeParameter('fileId', i) as string;
						const updateFields = this.getNodeParameter('updateFields', i, {}) as IDataObject;

						const qs: IDataObject = {
							supportsAllDrives: true,
						};

						Object.assign(qs, options);

						qs.fields = queryFields;

						const body: IDataObject = {};

						if (updateFields.fileName) {
							body.name = updateFields.fileName;
						}

						if (updateFields.parentId && updateFields.parentId !== '') {
							qs.addParents = updateFields.parentId;
						}

						const responseData = await googleApiRequest.call(this, 'PATCH', `/drive/v3/files/${id}`, body, qs);
						returnData.push(responseData as IDataObject);
					}

				}
				if (resource === 'folder') {
					if (operation === 'create') {
						// ----------------------------------
						//         folder:create
						// ----------------------------------

						const name = this.getNodeParameter('name', i) as string;

						const body = {
							name,
							mimeType: 'application/vnd.google-apps.folder',
							parents: options.parents || [],
						};

						const qs = {
							fields: queryFields,
							supportsAllDrives: true,
						};

						const response = await googleApiRequest.call(this, 'POST', '/drive/v3/files', body, qs);

						returnData.push(response as IDataObject);
					}
				}
				if (['file', 'folder'].includes(resource)) {
					if (operation === 'delete') {
						// ----------------------------------
						//         delete
						// ----------------------------------

						const fileId = this.getNodeParameter('fileId', i) as string;

						const response = await googleApiRequest.call(this, 'DELETE', `/drive/v3/files/${fileId}`);

						// If we are still here it did succeed
						returnData.push({
							fileId,
							success: true,
						});
					}
					if (operation === 'share') {

						const fileId = this.getNodeParameter('fileId', i) as string;

						const permissions = this.getNodeParameter('permissionsUi', i) as IDataObject;

						const options = this.getNodeParameter('options', i) as IDataObject;

						const body: IDataObject = {};

						const qs: IDataObject = {};

						if (permissions.permissionsValues) {
							Object.assign(body, permissions.permissionsValues);
						}

						Object.assign(qs, options);

						const response = await googleApiRequest.call(this, 'POST', `/drive/v3/files/${fileId}/permissions`, body, qs);

						returnData.push(response as IDataObject);
					}
				}
			} catch (error) {
				if (this.continueOnFail()) {
					if (resource === 'file' && operation === 'download') {
						items[i].json = { error: error.message };
					} else {
						returnData.push({ error: error.message });
					}
					continue;
				}
				throw error;
			}
		}
		if (resource === 'file' && operation === 'download') {
			// For file downloads the files get attached to the existing items
			return this.prepareOutputData(items);
		} else {
			// For all other ones does the output items get replaced
			return [this.helpers.returnJsonArray(returnData)];
		}
	}
}