import type {
	IExecuteFunctions,
	IDataObject,
	INodeExecutionData,
	INodeType,
	INodeTypeDescription,
	JsonObject,
} from 'n8n-workflow';
import { NodeApiError, NodeConnectionType, NodeOperationError } from 'n8n-workflow';

import { sendyApiRequest } from './GenericFunctions';

import { campaignFields, campaignOperations } from './CampaignDescription';

import { subscriberFields, subscriberOperations } from './SubscriberDescription';

export class Sendy implements INodeType {
	description: INodeTypeDescription = {
		displayName: 'Sendy',
		name: 'sendy',
		// eslint-disable-next-line n8n-nodes-base/node-class-description-icon-not-svg
		icon: 'file:sendy.png',
		group: ['input'],
		version: 1,
		subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
		description: 'Consume Sendy API',
		defaults: {
			name: 'Sendy',
		},
		inputs: [NodeConnectionType.Main],
		outputs: [NodeConnectionType.Main],
		credentials: [
			{
				name: 'sendyApi',
				required: true,
			},
		],
		properties: [
			{
				displayName: 'Resource',
				name: 'resource',
				type: 'options',
				noDataExpression: true,
				options: [
					{
						name: 'Campaign',
						value: 'campaign',
					},
					{
						name: 'Subscriber',
						value: 'subscriber',
					},
				],
				default: 'subscriber',
			},
			...campaignOperations,
			...campaignFields,
			...subscriberOperations,
			...subscriberFields,
		],
	};

	async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
		const items = this.getInputData();
		const returnData: IDataObject[] = [];
		const length = items.length;
		let responseData;
		const resource = this.getNodeParameter('resource', 0);
		const operation = this.getNodeParameter('operation', 0);
		for (let i = 0; i < length; i++) {
			if (resource === 'campaign') {
				if (operation === 'create') {
					const fromName = this.getNodeParameter('fromName', i) as string;

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

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

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

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

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

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

					const additionalFields = this.getNodeParameter('additionalFields', i);

					let brandId = null;
					if (!sendCampaign) {
						brandId = this.getNodeParameter('brandId', i) as string;
					}

					const body: IDataObject = {
						from_name: fromName,
						from_email: fromEmail,
						reply_to: replyTo,
						title,
						subject,
						send_campaign: sendCampaign ? 1 : 0,
						html_text: htmlText,
					};

					if (brandId) {
						body.brand_id = brandId;
					}

					if (additionalFields.plainText) {
						body.plain_text = additionalFields.plainText;
					}

					if (additionalFields.listIds) {
						body.list_ids = additionalFields.listIds as string;
					}

					if (additionalFields.segmentIds) {
						body.segment_ids = additionalFields.segmentIds as string;
					}

					if (additionalFields.excludeListIds) {
						body.exclude_list_ids = additionalFields.excludeListIds as string;
					}

					if (additionalFields.excludeSegmentIds) {
						body.exclude_segments_ids = additionalFields.excludeSegmentIds as string;
					}

					if (additionalFields.queryString) {
						body.query_string = additionalFields.queryString as string;
					}

					if (additionalFields.trackOpens) {
						body.track_opens = (additionalFields.trackOpens as boolean) ? 1 : 0;
					}

					if (additionalFields.trackClicks) {
						body.track_clicks = (additionalFields.trackClicks as boolean) ? 1 : 0;
					}

					responseData = await sendyApiRequest.call(
						this,
						'POST',
						'/api/campaigns/create.php',
						body,
					);

					const success = ['Campaign created', 'Campaign created and now sending'];

					if (success.includes(responseData as string)) {
						responseData = { message: responseData };
					} else {
						throw new NodeApiError(this.getNode(), responseData as JsonObject, { httpCode: '400' });
					}
				}
			}

			if (resource === 'subscriber') {
				if (operation === 'add') {
					const email = this.getNodeParameter('email', i) as string;

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

					const additionalFields = this.getNodeParameter('additionalFields', i);

					const body: IDataObject = {
						email,
						list: listId,
					};

					Object.assign(body, additionalFields);

					responseData = await sendyApiRequest.call(this, 'POST', '/subscribe', body);

					if (responseData === '1') {
						responseData = { success: true };
					} else {
						throw new NodeOperationError(
							this.getNode(),
							`Sendy error response [${400}]: ${responseData}`,
							{ itemIndex: i },
						);
					}
				}

				if (operation === 'count') {
					const listId = this.getNodeParameter('listId', i) as string;

					const body: IDataObject = {
						list_id: listId,
					};

					responseData = await sendyApiRequest.call(
						this,
						'POST',
						'/api/subscribers/active-subscriber-count.php',
						body,
					);

					const errors = [
						'No data passed',
						'API key not passed',
						'Invalid API key',
						'List ID not passed',
						'List does not exist',
					];

					if (!errors.includes(responseData as string)) {
						responseData = { count: responseData };
					} else {
						throw new NodeOperationError(
							this.getNode(),
							`Sendy error response [${400}]: ${responseData}`,
							{ itemIndex: i },
						);
					}
				}

				if (operation === 'delete') {
					const email = this.getNodeParameter('email', i) as string;

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

					const body: IDataObject = {
						email,
						list_id: listId,
					};

					responseData = await sendyApiRequest.call(
						this,
						'POST',
						'/api/subscribers/delete.php',
						body,
					);

					if (responseData === '1') {
						responseData = { success: true };
					} else {
						throw new NodeOperationError(
							this.getNode(),
							`Sendy error response [${400}]: ${responseData}`,
							{ itemIndex: i },
						);
					}
				}

				if (operation === 'remove') {
					const email = this.getNodeParameter('email', i) as string;

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

					const body: IDataObject = {
						email,
						list: listId,
					};

					responseData = await sendyApiRequest.call(this, 'POST', '/unsubscribe', body);

					if (responseData === '1') {
						responseData = { success: true };
					} else {
						throw new NodeOperationError(
							this.getNode(),
							`Sendy error response [${400}]: ${responseData}`,
							{ itemIndex: i },
						);
					}
				}

				if (operation === 'status') {
					const email = this.getNodeParameter('email', i) as string;

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

					const body: IDataObject = {
						email,
						list_id: listId,
					};

					responseData = await sendyApiRequest.call(
						this,
						'POST',
						'/api/subscribers/subscription-status.php',
						body,
					);

					const status = [
						'Subscribed',
						'Unsubscribed',
						'Unconfirmed',
						'Bounced',
						'Soft bounced',
						'Complained',
					];

					if (status.includes(responseData as string)) {
						responseData = { status: responseData };
					} else {
						throw new NodeOperationError(
							this.getNode(),
							`Sendy error response [${400}]: ${responseData}`,
							{ itemIndex: i },
						);
					}
				}
			}
		}
		if (Array.isArray(responseData)) {
			returnData.push.apply(returnData, responseData as IDataObject[]);
		} else if (responseData !== undefined) {
			returnData.push(responseData as IDataObject);
		}
		return [this.helpers.returnJsonArray(returnData)];
	}
}
