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

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

import {
	channelFields,
	channelOperations,
} from './ChannelDescription';
import {
	messageFields,
	messageOperations,
} from './MessageDescription';
import {
	starFields,
	starOperations,
} from './StarDescription';
import {
	fileFields,
	fileOperations,
} from './FileDescription';
import {
	slackApiRequest,
	slackApiRequestAllItems,
	validateJSON,
} from './GenericFunctions';
import {
	IAttachment,
} from './MessageInterface';

interface Attachment {
	fields: {
		item?: object[];
	};
}

interface Text {
	type?: string;
	text?: string;
	emoji?: boolean;
	verbatim?: boolean;
}

interface Confirm {
	title?: Text;
	text?: Text;
	confirm?: Text;
	deny?: Text;
	style?: string;
}

interface Element {
	type?: string;
	text?: Text;
	action_id?: string;
	url?: string;
	value?: string;
	style?: string;
	confirm?: Confirm;
}

interface Block {
	type?: string;
	elements?: Element[];
	block_id?: string;
	text?: Text;
	fields?: Text[];
	accessory?: Element;
}

export class Slack implements INodeType {
	description: INodeTypeDescription = {
		displayName: 'Slack',
		name: 'slack',
		icon: 'file:slack.png',
		group: ['output'],
		version: 1,
		subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
		description: 'Consume Slack API',
		defaults: {
			name: 'Slack',
			color: '#BB2244',
		},
		inputs: ['main'],
		outputs: ['main'],
		credentials: [
			{
				name: 'slackApi',
				required: true,
				displayOptions: {
					show: {
						authentication: [
							'accessToken',
						],
					},
				},
			},
			{
				name: 'slackOAuth2Api',
				required: true,
				displayOptions: {
					show: {
						authentication: [
							'oAuth2',
						],
					},
				},
			},
		],
		properties: [
			{
				displayName: 'Authentication',
				name: 'authentication',
				type: 'options',
				options: [
					{
						name: 'Access Token',
						value: 'accessToken',
					},
					{
						name: 'OAuth2',
						value: 'oAuth2',
					},
				],
				default: 'accessToken',
				description: 'The resource to operate on.',
			},

			{
				displayName: 'Resource',
				name: 'resource',
				type: 'options',
				options: [
					{
						name: 'Channel',
						value: 'channel',
					},
					{
						name: 'File',
						value: 'file',
					},
					{
						name: 'Message',
						value: 'message',
					},
					{
						name: 'Star',
						value: 'star',
					},
				],
				default: 'message',
				description: 'The resource to operate on.',
			},

			...channelOperations,
			...channelFields,
			...messageOperations,
			...messageFields,
			...starOperations,
			...starFields,
			...fileOperations,
			...fileFields,
		],
	};

	methods = {
		loadOptions: {
			// Get all the users to display them to user so that he can
			// select them easily
			async getUsers(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
				const returnData: INodePropertyOptions[] = [];
				const users = await slackApiRequestAllItems.call(this, 'members', 'GET', '/users.list');
				for (const user of users) {
					const userName = user.name;
					const userId = user.id;
					returnData.push({
						name: userName,
						value: userId,
					});
				}

				returnData.sort((a, b) => {
					if (a.name < b.name) { return -1; }
					if (a.name > b.name) { return 1; }
					return 0;
				});

				return returnData;
			},
			// Get all the users to display them to user so that he can
			// select them easily
			async getChannels(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
				const returnData: INodePropertyOptions[] = [];
				const channels = await slackApiRequestAllItems.call(this, 'channels', 'GET', '/conversations.list');
				for (const channel of channels) {
					const channelName = channel.name;
					const channelId = channel.id;
					returnData.push({
						name: channelName,
						value: channelId,
					});
				}

				returnData.sort((a, b) => {
					if (a.name < b.name) { return -1; }
					if (a.name > b.name) { return 1; }
					return 0;
				});

				return returnData;
			},
		}
	};

	async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
		const items = this.getInputData();
		const returnData: IDataObject[] = [];
		const length = items.length as unknown as number;
		let qs: IDataObject;
		let responseData;
		const authentication = this.getNodeParameter('authentication', 0) as string;
		const resource = this.getNodeParameter('resource', 0) as string;
		const operation = this.getNodeParameter('operation', 0) as string;

		for (let i = 0; i < length; i++) {
			qs = {};
			if (resource === 'channel') {
				//https://api.slack.com/methods/conversations.archive
				if (operation === 'archive') {
					const channel = this.getNodeParameter('channelId', i) as string;
					const body: IDataObject = {
						channel,
					};
					responseData = await slackApiRequest.call(this, 'POST', '/conversations.archive', body, qs);
				}
				//https://api.slack.com/methods/conversations.close
				if (operation === 'close') {
					const channel = this.getNodeParameter('channelId', i) as string;
					const body: IDataObject = {
						channel,
					};
					responseData = await slackApiRequest.call(this, 'POST', '/conversations.close', body, qs);
				}
				//https://api.slack.com/methods/conversations.create
				if (operation === 'create') {
					const channel = this.getNodeParameter('channelId', i) as string;
					const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
					const body: IDataObject = {
						name: channel,
					};
					if (additionalFields.isPrivate) {
						body.is_private = additionalFields.isPrivate as boolean;
					}
					if (additionalFields.users) {
						body.user_ids = (additionalFields.users as string[]).join(',');
					}
					responseData = await slackApiRequest.call(this, 'POST', '/conversations.create', body, qs);
					responseData = responseData.channel;
				}
				//https://api.slack.com/methods/conversations.kick
				if (operation === 'kick') {
					const channel = this.getNodeParameter('channelId', i) as string;
					const userId = this.getNodeParameter('userId', i) as string;
					const body: IDataObject = {
						name: channel,
						user: userId,
					};
					responseData = await slackApiRequest.call(this, 'POST', '/conversations.kick', body, qs);
				}
				//https://api.slack.com/methods/conversations.join
				if (operation === 'join') {
					const channel = this.getNodeParameter('channelId', i) as string;
					const body: IDataObject = {
						channel,
					};
					responseData = await slackApiRequest.call(this, 'POST', '/conversations.join', body, qs);
					responseData = responseData.channel;
				}
				//https://api.slack.com/methods/conversations.info
				if (operation === 'get') {
					const channel = this.getNodeParameter('channelId', i) as string;
					qs.channel = channel,
						responseData = await slackApiRequest.call(this, 'POST', '/conversations.info', {}, qs);
					responseData = responseData.channel;
				}
				//https://api.slack.com/methods/conversations.list
				if (operation === 'getAll') {
					const returnAll = this.getNodeParameter('returnAll', i) as boolean;
					const filters = this.getNodeParameter('filters', i) as IDataObject;
					if (filters.types) {
						qs.types = (filters.types as string[]).join(',');
					}
					if (filters.excludeArchived) {
						qs.exclude_archived = filters.excludeArchived as boolean;
					}
					if (returnAll === true) {
						responseData = await slackApiRequestAllItems.call(this, 'channels', 'GET', '/conversations.list', {}, qs);
					} else {
						qs.limit = this.getNodeParameter('limit', i) as number;
						responseData = await slackApiRequest.call(this, 'GET', '/conversations.list', {}, qs);
						responseData = responseData.channels;
					}
				}
				//https://api.slack.com/methods/conversations.history
				if (operation === 'history') {
					const channel = this.getNodeParameter('channelId', i) as string;
					const returnAll = this.getNodeParameter('returnAll', i) as boolean;
					const filters = this.getNodeParameter('filters', i) as IDataObject;
					qs.channel = channel;
					if (filters.inclusive) {
						qs.inclusive = filters.inclusive as boolean;
					}
					if (filters.latest) {
						qs.latest = filters.latest as string;
					}
					if (filters.oldest) {
						qs.oldest = filters.oldest as string;
					}
					if (returnAll === true) {
						responseData = await slackApiRequestAllItems.call(this, 'messages', 'GET', '/conversations.history', {}, qs);
					} else {
						qs.limit = this.getNodeParameter('limit', i) as number;
						responseData = await slackApiRequest.call(this, 'GET', '/conversations.history', {}, qs);
						responseData = responseData.messages;
					}
				}
				//https://api.slack.com/methods/conversations.invite
				if (operation === 'invite') {
					const channel = this.getNodeParameter('channelId', i) as string;
					const userId = this.getNodeParameter('userId', i) as string;
					const body: IDataObject = {
						channel,
						user: userId,
					};
					responseData = await slackApiRequest.call(this, 'POST', '/conversations.invite', body, qs);
					responseData = responseData.channel;
				}
				//https://api.slack.com/methods/conversations.leave
				if (operation === 'leave') {
					const channel = this.getNodeParameter('channelId', i) as string;
					const body: IDataObject = {
						channel,
					};
					responseData = await slackApiRequest.call(this, 'POST', '/conversations.leave', body, qs);
				}
				//https://api.slack.com/methods/conversations.open
				if (operation === 'open') {
					const options = this.getNodeParameter('options', i) as IDataObject;
					const body: IDataObject = {};
					if (options.channelId) {
						body.channel = options.channelId as string;
					}
					if (options.returnIm) {
						body.return_im = options.returnIm as boolean;
					}
					if (options.users) {
						body.users = (options.users as string[]).join(',');
					}
					responseData = await slackApiRequest.call(this, 'POST', '/conversations.open', body, qs);
					responseData = responseData.channel;
				}
				//https://api.slack.com/methods/conversations.rename
				if (operation === 'rename') {
					const channel = this.getNodeParameter('channelId', i) as IDataObject;
					const name = this.getNodeParameter('name', i) as IDataObject;
					const body: IDataObject = {
						channel,
						name,
					};
					responseData = await slackApiRequest.call(this, 'POST', '/conversations.rename', body, qs);
					responseData = responseData.channel;
				}
				//https://api.slack.com/methods/conversations.replies
				if (operation === 'replies') {
					const channel = this.getNodeParameter('channelId', i) as string;
					const ts = this.getNodeParameter('ts', i) as string;
					const returnAll = this.getNodeParameter('returnAll', i) as boolean;
					const filters = this.getNodeParameter('filters', i) as IDataObject;
					qs.channel = channel;
					qs.ts = ts;
					if (filters.inclusive) {
						qs.inclusive = filters.inclusive as boolean;
					}
					if (filters.latest) {
						qs.latest = filters.latest as string;
					}
					if (filters.oldest) {
						qs.oldest = filters.oldest as string;
					}
					if (returnAll === true) {
						responseData = await slackApiRequestAllItems.call(this, 'messages', 'GET', '/conversations.replies', {}, qs);
					} else {
						qs.limit = this.getNodeParameter('limit', i) as number;
						responseData = await slackApiRequest.call(this, 'GET', '/conversations.replies', {}, qs);
						responseData = responseData.messages;
					}
				}
				//https://api.slack.com/methods/conversations.setPurpose
				if (operation === 'setPurpose') {
					const channel = this.getNodeParameter('channelId', i) as IDataObject;
					const purpose = this.getNodeParameter('purpose', i) as IDataObject;
					const body: IDataObject = {
						channel,
						purpose,
					};
					responseData = await slackApiRequest.call(this, 'POST', '/conversations.setPurpose', body, qs);
					responseData = responseData.channel;
				}
				//https://api.slack.com/methods/conversations.setTopic
				if (operation === 'setTopic') {
					const channel = this.getNodeParameter('channelId', i) as IDataObject;
					const topic = this.getNodeParameter('topic', i) as IDataObject;
					const body: IDataObject = {
						channel,
						topic,
					};
					responseData = await slackApiRequest.call(this, 'POST', '/conversations.setTopic', body, qs);
					responseData = responseData.channel;
				}
				//https://api.slack.com/methods/conversations.unarchive
				if (operation === 'unarchive') {
					const channel = this.getNodeParameter('channelId', i) as string;
					const body: IDataObject = {
						channel,
					};
					responseData = await slackApiRequest.call(this, 'POST', '/conversations.unarchive', body, qs);
				}
			}
			if (resource === 'message') {
				//https://api.slack.com/methods/chat.postMessage
				if (operation === 'post') {
					const channel = this.getNodeParameter('channel', i) as string;
					const text = this.getNodeParameter('text', i) as string;
					const body: IDataObject = {
						channel,
						text,
					};

					const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean;

					if (authentication === 'accessToken') {
						body.as_user = this.getNodeParameter('as_user', i) as boolean;
					}
					if (body.as_user === false) {
						body.username = this.getNodeParameter('username', i) as string;
						delete body.as_user;
					}

					if (!jsonParameters) {
						const attachments = this.getNodeParameter('attachments', i, []) as unknown as Attachment[];
						const blocksUi = (this.getNodeParameter('blocksUi', i, []) as IDataObject).blocksValues as IDataObject[];

						// The node does save the fields data differently than the API
						// expects so fix the data befre we send the request
						for (const attachment of attachments) {
							if (attachment.fields !== undefined) {
								if (attachment.fields.item !== undefined) {
									// Move the field-content up
									// @ts-ignore
									attachment.fields = attachment.fields.item;
								} else {
									// If it does not have any items set remove it
									delete attachment.fields;
								}
							}
						}
						body['attachments'] = attachments;

						if (blocksUi) {
							const blocks: Block[] = [];
							for (const blockUi of blocksUi) {
								const block: Block = {};
								const elements: Element[] = [];
								block.block_id = blockUi.blockId as string;
								block.type = blockUi.type as string;
								if (block.type === 'actions') {
									const elementsUi = (blockUi.elementsUi as IDataObject).elementsValues as IDataObject[];
									if (elementsUi) {
										for (const elementUi of elementsUi) {
											const element: Element = {};
											if (elementUi.actionId === '') {
												throw new Error('Action ID must be set');
											}
											if (elementUi.text === '') {
												throw new Error('Text must be set');
											}
											element.action_id = elementUi.actionId as string;
											element.type = elementUi.type as string;
											element.text = {
												text: elementUi.text as string,
												type: 'plain_text',
												emoji: elementUi.emoji as boolean,
											};
											if (elementUi.url) {
												element.url = elementUi.url as string;
											}
											if (elementUi.value) {
												element.value = elementUi.value as string;
											}
											if (elementUi.style !== 'default') {
												element.style = elementUi.style as string;
											}
											const confirmUi = (elementUi.confirmUi as IDataObject).confirmValue as IDataObject;
											if (confirmUi) {
												const confirm: Confirm = {};
												const titleUi = (confirmUi.titleUi as IDataObject).titleValue as IDataObject;
												const textUi = (confirmUi.textUi as IDataObject).textValue as IDataObject;
												const confirmTextUi = (confirmUi.confirmTextUi as IDataObject).confirmValue as IDataObject;
												const denyUi = (confirmUi.denyUi as IDataObject).denyValue as IDataObject;
												const style = confirmUi.style as string;
												if (titleUi) {
													confirm.title = {
														type: 'plain_text',
														text: titleUi.text as string,
														emoji: titleUi.emoji as boolean,
													};
												}
												if (textUi) {
													confirm.text = {
														type: 'plain_text',
														text: textUi.text as string,
														emoji: textUi.emoji as boolean,
													};
												}
												if (confirmTextUi) {
													confirm.confirm = {
														type: 'plain_text',
														text: confirmTextUi.text as string,
														emoji: confirmTextUi.emoji as boolean,
													};
												}
												if (denyUi) {
													confirm.deny = {
														type: 'plain_text',
														text: denyUi.text as string,
														emoji: denyUi.emoji as boolean,
													};
												}
												if (style !== 'default') {
													confirm.style = style as string;
												}
												element.confirm = confirm;
											}
											elements.push(element);
										}
										block.elements = elements;
									}
								} else if (block.type === 'section') {
									const textUi = (blockUi.textUi as IDataObject).textValue as IDataObject;
									if (textUi) {
										const text: Text = {};
										if (textUi.type === 'plainText') {
											text.type = 'plain_text';
											text.emoji = textUi.emoji as boolean;
										} else {
											text.type = 'mrkdwn';
											text.verbatim = textUi.verbatim as boolean;
										}
										text.text = textUi.text as string;
										block.text = text;
									} else {
										throw new Error('Property text must be defined');
									}
									const fieldsUi = (blockUi.fieldsUi as IDataObject).fieldsValues as IDataObject[];
									if (fieldsUi) {
										const fields: Text[] = [];
										for (const fieldUi of fieldsUi) {
											const field: Text = {};
											if (fieldUi.type === 'plainText') {
												field.type = 'plain_text';
												field.emoji = fieldUi.emoji as boolean;
											} else {
												field.type = 'mrkdwn';
												field.verbatim = fieldUi.verbatim as boolean;
											}
											field.text = fieldUi.text as string;
											fields.push(field);
										}
										// If not fields were added then it's not needed to send the property
										if (fields.length > 0) {
											block.fields = fields;
										}
									}
									const accessoryUi = (blockUi.accessoryUi as IDataObject).accessoriesValues as IDataObject;
									if (accessoryUi) {
										const accessory: Element = {};
										if (accessoryUi.type === 'button') {
											accessory.type = 'button';
											accessory.text = {
												text: accessoryUi.text as string,
												type: 'plain_text',
												emoji: accessoryUi.emoji as boolean,
											};
											if (accessoryUi.url) {
												accessory.url = accessoryUi.url as string;
											}
											if (accessoryUi.value) {
												accessory.value = accessoryUi.value as string;
											}
											if (accessoryUi.style !== 'default') {
												accessory.style = accessoryUi.style as string;
											}
											const confirmUi = (accessoryUi.confirmUi as IDataObject).confirmValue as IDataObject;
											if (confirmUi) {
												const confirm: Confirm = {};
												const titleUi = (confirmUi.titleUi as IDataObject).titleValue as IDataObject;
												const textUi = (confirmUi.textUi as IDataObject).textValue as IDataObject;
												const confirmTextUi = (confirmUi.confirmTextUi as IDataObject).confirmValue as IDataObject;
												const denyUi = (confirmUi.denyUi as IDataObject).denyValue as IDataObject;
												const style = confirmUi.style as string;
												if (titleUi) {
													confirm.title = {
														type: 'plain_text',
														text: titleUi.text as string,
														emoji: titleUi.emoji as boolean,
													};
												}
												if (textUi) {
													confirm.text = {
														type: 'plain_text',
														text: textUi.text as string,
														emoji: textUi.emoji as boolean,
													};
												}
												if (confirmTextUi) {
													confirm.confirm = {
														type: 'plain_text',
														text: confirmTextUi.text as string,
														emoji: confirmTextUi.emoji as boolean,
													};
												}
												if (denyUi) {
													confirm.deny = {
														type: 'plain_text',
														text: denyUi.text as string,
														emoji: denyUi.emoji as boolean,
													};
												}
												if (style !== 'default') {
													confirm.style = style as string;
												}
												accessory.confirm = confirm;
											}
										}
										block.accessory = accessory;
									}
								}
								blocks.push(block);
							}
							body.blocks = blocks;
						}

					} else {
						const attachmentsJson = this.getNodeParameter('attachmentsJson', i, []) as string;
						const blocksJson = this.getNodeParameter('blocksJson', i, []) as string;
						if (attachmentsJson !== '' && validateJSON(attachmentsJson) === undefined) {
							throw new Error('Attachments it is not a valid json');
						}
						if (blocksJson !== '' && validateJSON(blocksJson) === undefined) {
							throw new Error('Blocks it is not a valid json');
						}
						if (attachmentsJson !== '') {
							body.attachments = attachmentsJson;
						}
						if (blocksJson !== '') {
							body.blocks = blocksJson;
						}
					}
					// Add all the other options to the request
					const otherOptions = this.getNodeParameter('otherOptions', i) as IDataObject;
					Object.assign(body, otherOptions);
					responseData = await slackApiRequest.call(this, 'POST', '/chat.postMessage', body, qs);
				}
				//https://api.slack.com/methods/chat.update
				if (operation === 'update') {
					const channel = this.getNodeParameter('channelId', i) as string;
					const text = this.getNodeParameter('text', i) as string;
					const ts = this.getNodeParameter('ts', i) as string;
					const attachments = this.getNodeParameter('attachments', i, []) as unknown as IAttachment[];
					const body: IDataObject = {
						channel,
						text,
						ts,
					};

					// The node does save the fields data differently than the API
					// expects so fix the data befre we send the request
					for (const attachment of attachments) {
						if (attachment.fields !== undefined) {
							if (attachment.fields.item !== undefined) {
								// Move the field-content up
								// @ts-ignore
								attachment.fields = attachment.fields.item;
							} else {
								// If it does not have any items set remove it
								delete attachment.fields;
							}
						}
					}
					body['attachments'] = attachments;

					// Add all the other options to the request
					const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
					Object.assign(body, updateFields);
					responseData = await slackApiRequest.call(this, 'POST', '/chat.update', body, qs);
				}
			}
			if (resource === 'star') {
				//https://api.slack.com/methods/stars.add
				if (operation === 'add') {
					const options = this.getNodeParameter('options', i) as IDataObject;
					const body: IDataObject = {};
					if (options.channelId) {
						body.channel = options.channelId as string;
					}
					if (options.fileId) {
						body.file = options.fileId as string;
					}
					if (options.fileComment) {
						body.file_comment = options.fileComment as string;
					}
					if (options.timestamp) {
						body.timestamp = options.timestamp as string;
					}
					responseData = await slackApiRequest.call(this, 'POST', '/stars.add', body, qs);
				}
				//https://api.slack.com/methods/stars.remove
				if (operation === 'delete') {
					const options = this.getNodeParameter('options', i) as IDataObject;
					const body: IDataObject = {};
					if (options.channelId) {
						body.channel = options.channelId as string;
					}
					if (options.fileId) {
						body.file = options.fileId as string;
					}
					if (options.fileComment) {
						body.file_comment = options.fileComment as string;
					}
					if (options.timestamp) {
						body.timestamp = options.timestamp as string;
					}
					responseData = await slackApiRequest.call(this, 'POST', '/stars.remove', body, qs);
				}
				//https://api.slack.com/methods/stars.list
				if (operation === 'getAll') {
					const returnAll = this.getNodeParameter('returnAll', i) as boolean;
					if (returnAll === true) {
						responseData = await slackApiRequestAllItems.call(this, 'items', 'GET', '/stars.list', {}, qs);
					} else {
						qs.limit = this.getNodeParameter('limit', i) as number;
						responseData = await slackApiRequest.call(this, 'GET', '/stars.list', {}, qs);
						responseData = responseData.items;
					}
				}
			}
			if (resource === 'file') {
				//https://api.slack.com/methods/files.upload
				if (operation === 'upload') {
					const options = this.getNodeParameter('options', i) as IDataObject;
					const binaryData = this.getNodeParameter('binaryData', i) as boolean;
					const body: IDataObject = {};
					if (options.channelIds) {
						body.channels = (options.channelIds as string[]).join(',');
					}
					if (options.fileName) {
						body.filename = options.fileName as string;
					}
					if (options.initialComment) {
						body.initial_comment = options.initialComment as string;
					}
					if (options.threadTs) {
						body.thread_ts = options.threadTs as string;
					}
					if (options.title) {
						body.title = options.title as string;
					}
					if (binaryData) {
						const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i) as string;
						if (items[i].binary === undefined
							//@ts-ignore
							|| items[i].binary[binaryPropertyName] === undefined) {
							throw new Error(`No binary data property "${binaryPropertyName}" does not exists on item!`);
						}
						body.file = {
							//@ts-ignore
							value: Buffer.from(items[i].binary[binaryPropertyName].data, BINARY_ENCODING),
							options: {
								//@ts-ignore
								filename: items[i].binary[binaryPropertyName].fileName,
								//@ts-ignore
								contentType: items[i].binary[binaryPropertyName].mimeType,
							}
						};
						responseData = await slackApiRequest.call(this, 'POST', '/files.upload', {}, qs, { 'Content-Type': 'multipart/form-data' }, { formData: body });
						responseData = responseData.file;
					} else {
						const fileContent = this.getNodeParameter('fileContent', i) as string;
						body.content = fileContent;
						responseData = await slackApiRequest.call(this, 'POST', '/files.upload', body, qs, { 'Content-Type': 'application/x-www-form-urlencoded' }, { form: body });
						responseData = responseData.file;
					}
				}
				//https://api.slack.com/methods/files.list
				if (operation === 'getAll') {
					const returnAll = this.getNodeParameter('returnAll', i) as boolean;
					const filters = this.getNodeParameter('filters', i) as IDataObject;
					if (filters.channelId) {
						qs.channel = filters.channelId as string;
					}
					if (filters.showFilesHidden) {
						qs.show_files_hidden_by_limit = filters.showFilesHidden as boolean;
					}
					if (filters.tsFrom) {
						qs.ts_from = filters.tsFrom as string;
					}
					if (filters.tsTo) {
						qs.ts_to = filters.tsTo as string;
					}
					if (filters.types) {
						qs.types = (filters.types as string[]).join(',') as string;
					}
					if (filters.userId) {
						qs.user = filters.userId as string;
					}
					if (returnAll === true) {
						responseData = await slackApiRequestAllItems.call(this, 'files', 'GET', '/files.list', {}, qs);
					} else {
						qs.count = this.getNodeParameter('limit', i) as number;
						responseData = await slackApiRequest.call(this, 'GET', '/files.list', {}, qs);
						responseData = responseData.files;
					}
				}
				//https://api.slack.com/methods/files.info
				if (operation === 'get') {
					const fileId = this.getNodeParameter('fileId', i) as string;
					qs.file = fileId;
					responseData = await slackApiRequest.call(this, 'GET', '/files.info', {}, qs);
					responseData = responseData.file;
				}
			}
			if (Array.isArray(responseData)) {
				returnData.push.apply(returnData, responseData as IDataObject[]);
			} else {
				returnData.push(responseData as IDataObject);
			}
		}
		return [this.helpers.returnJsonArray(returnData)];
	}
}