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

import { ecommerceIdentifiers, orderPlacedIdentifiers, orderExplicitIdentifiers } from './Fields/IdentifierFields'
import { ecommerceLineItems } from './Fields/LineItemsFields';
import { ecommerceShippingFields } from './Fields/ShippingFields';
import { ecommerceTrackingFields } from './Fields/TrackingFields';
import { appendLegalBaseOption } from './Fields/AddicionalFields';
import { buildLineItems } from './Utils/PayloadBuilders';
import { validateEmail } from './Utils/Validations';
import { isEmpty } from 'validator';
import { rdStationApiRequest } from './Utils/GenericFunctions';

import {
	ECOMMERCE_EVENT_TYPE_MAP,
	EVENT_FAMILY,
	LEGAL_BASES_OBJECT,
} from './Utils/GenericConstants';

export class RdsmEcommerce implements INodeType {
	description: INodeTypeDescription = {
		name: 'rdsmEcommerce',
		displayName: 'RD Station Marketing para Ecommerce',
		icon: 'file:RdsmEcommerce.svg',
		group: ['transform'],
		version: 1,
		subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
		description: 'Insert ecommerce events to RD Station Marketing through API',
		// usableAsTool: true,
		defaults: {
			name: 'RD Station Marketing para Ecommerce',
		},
		inputs: ['main' as NodeConnectionType],
		outputs: ['main' as NodeConnectionType],
		credentials: [
			{
				name: 'rdsmEcommerceOAuth2Api',
				required: true,
			}
		],
		properties: [
			/* Start Default Fields */
			{
				displayName: 'Resource',
				name: 'resource',
				type: 'options',
				options: [
					{
						name: 'Ecommerce Event',
						value: 'ecommerceEvents',
					}
				],
				default: 'ecommerceEvents',
				description: 'Create a new ecommerce event',
				noDataExpression: true,
				required: true,
			},
			{
				displayName: 'Operation',
				name: 'operation',
				type: 'options',
				displayOptions: {
					show: {
						resource: ['ecommerceEvents'],
					},
				},
				options: [
					{
						name: 'New Ecommerce Event',
						value: 'newEcommerceEvent',
						description: 'Register a new ecommerce event',
						action: 'Register a new ecommerce event',
					},
				],
				default: 'newEcommerceEvent',
				noDataExpression: true,
			},
			{
				displayName: 'Ecommerce Event Type',
				name: 'eventType',
				type: 'options',
				displayOptions: {
					show: {
						operation: ['newEcommerceEvent'],
						resource: ['ecommerceEvents'],
					},
				},
				options: [
					{
						name: 'Cart Abandoned',
						value: 'ecommerceCartAbandoned',
						description: 'Cart abandoned event',
					},
					{
						name: 'Checkout Started',
						value: 'ecommerceCheckoutStarted',
						description: 'Checkout started event',
					},
					{
						name: 'Order Cancelled',
						value: 'ecommerceOrderCancelled',
						description: 'Order cancelled event',
					},
					{
						name: 'Order Fulfilled',
						value: 'ecommerceOrderFulfilled',
						description: 'Order fulfilled event',
					},
					{
						name: 'Order Paid',
						value: 'ecommerceOrderPaid',
						description: 'Order paid event',
					},
					{
						name: 'Order Placed',
						value: 'ecommerceOrderPlaced',
						description: 'Order placed event',
					},
					{
						name: 'Order Refunded',
						value: 'ecommerceOrderRefunded',
						description: 'Order refunded event',
					},
					{
						name: 'Shipment Delivered',
						value: 'ecommerceShipmentDelivered',
						description: 'Shipment delivered event',
					},
				],
				default: 'ecommerceCartAbandoned',
				description: 'Ecommerce event type for lead conversion',
				noDataExpression: true,
				required: true,
			},
			/* End Default Fields */

			/* Start Payload Fields */
			...ecommerceIdentifiers, // Identifier Fields
			{
				displayName: 'Lead Email',
				name: 'email',
				type: 'string',
				displayOptions: {
					show: {
						operation: ['newEcommerceEvent'],
						resource: ['ecommerceEvents'],
					},
				},
				default: '',
				placeholder: 'lead@email.com',
				description: 'Primary email for the lead',
				required: true,
			},
			{
				displayName: 'Lead Name',
				name: 'name',
				type: 'string',
				displayOptions: {
					show: {
						operation: ['newEcommerceEvent'],
						resource: ['ecommerceEvents'],
					},
				},
				default: '',
				description: 'Lead\'s fullname',
			},
			{
				displayName: 'Lead Mobile Phone',
				name: 'mobilePhone',
				type: 'string',
				displayOptions: {
					show: {
						operation: ['newEcommerceEvent'],
						resource: ['ecommerceEvents'],
					},
				},
				default: '',
				description: 'Lead\'s mobile phone',
			},
			{
				displayName: 'Lead Personal Phone',
				name: 'personalPhone',
				type: 'string',
				displayOptions: {
					show: {
						operation: ['newEcommerceEvent'],
						resource: ['ecommerceEvents'],
					},
				},
				default: '',
				description: 'Lead\'s personal phone',
			},
			{
				displayName: 'Checkout URL',
				name: 'checkoutUrl',
				type: 'string',
				displayOptions: {
					show: {
						operation: ['newEcommerceEvent'],
						resource: ['ecommerceEvents'],
						eventType: ['ecommerceCheckoutStarted', 'ecommerceCartAbandoned'],
					},
				},
				default: '',
				description: 'Checkout URL - HTTP or HTTPS address',
				required: true,
			},
			{
				displayName: 'Order URL',
				name: 'orderUrl',
				type: 'string',
				displayOptions: {
					show: {
						operation: ['newEcommerceEvent'],
						resource: ['ecommerceEvents'],
						eventType: ['ecommerceOrderPlaced', 'ecommerceOrderPaid'],
					},
				},
				default: '',
				description: 'Order URL - HTTP or HTTPS address',
			},
			...orderPlacedIdentifiers, // Order Placed Identifiers
			...orderExplicitIdentifiers, // Order Explicit Identifiers
			{
				displayName: 'Cancel Reason',
				name: 'cancelReason',
				type: 'options',
				displayOptions: {
					show: {
						operation: ['newEcommerceEvent'],
						resource: ['ecommerceEvents'],
						eventType: ['ecommerceOrderCancelled'],
					},
				},
				options: [
					{
						// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
						name: 'Customer changed or cancelled the order',
						value: 'customer',
					},
					{
						// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
						name: 'Fraud order',
						value: 'fraud',
					},
					{
						// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
						name: 'Other reason',
						value: 'other',
					},
					{
						// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
						name: 'Refused payment',
						value: 'declined',
					},
					{
						// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
						name: 'Unavailable items',
						value: 'inventory',
					},
				],
				default: 'other',
				description: 'Cancellation reason for order cancelled event',
			},
			{
				displayName: 'Currency',
				name: 'currency',
				type: 'options',
				displayOptions: {
					show: {
						operation: ['newEcommerceEvent'],
						resource: ['ecommerceEvents'],
					},
					hide: {
						eventType: [
							'ecommerceOrderCancelled',
							'ecommerceOrderFulfilled',
							'ecommerceShipmentDelivered',
						],
					},
				},
				options: [
					{
						name: 'ARS',
						value: 'ARS',
						description: 'Argentine Peso',
					},
					{
						name: 'BRL',
						value: 'BRL',
						description: 'Brazilian Real',
					},
					{
						name: 'CAD',
						value: 'CAD',
						description: 'Canadian Dollar',
					},
					{
						name: 'CLP',
						value: 'CLP',
						description: 'Chilean Peso',
					},
					{
						name: 'COP',
						value: 'COP',
						description: 'Colombian Peso',
					},
					{
						name: 'EUR',
						value: 'EUR',
						description: 'Euro',
					},
					{
						name: 'MXN',
						value: 'MXN',
						description: 'Mexican Peso',
					},
					{
						name: 'PEN',
						value: 'PEN',
						description: 'Peruvian Nuevo Sol',
					},
					{
						name: 'USD',
						value: 'USD',
						description: 'United States Dollar',
					},
					{
						name: 'UYU',
						value: 'UYU',
						description: 'Uruguayan Peso',
					},
				],
				default: 'BRL',
				description: 'Currency of the store',
				noDataExpression: true,
				required: true,
			},
			{
				displayName: 'Price',
				name: 'price',
				type: 'number',
				displayOptions: {
					show: {
						operation: ['newEcommerceEvent'],
						resource: ['ecommerceEvents'],
					},
					hide: {
						eventType: [
							'ecommerceOrderCancelled',
							'ecommerceOrderFulfilled',
							'ecommerceShipmentDelivered',
						],
					},
				},
				default: 0,
				typeOptions: {
					minValue: 0,
				},
				description: 'Price of the checkout/order',
				required: true,
			},
			...ecommerceShippingFields, // Shipping Fields
			...ecommerceTrackingFields, // Tracking Fields
			{
				displayName: 'Total Items',
				name: 'totalItems',
				type: 'number',
				displayOptions: {
					show: {
						operation: ['newEcommerceEvent'],
						resource: ['ecommerceEvents'],
					},
					hide: {
						eventType: [
							'ecommerceOrderCancelled',
							'ecommerceOrderFulfilled',
							'ecommerceShipmentDelivered',
						],
					},
				},
				default: 0,
				typeOptions: {
					minValue: 0,
				},
				description: 'Total items of products in the checkout',
				required: true,
			},
			...ecommerceLineItems, // LineItems Fields
			{
				displayName: 'Additional Fields',
				name: 'additionalFields',
				type: 'collection',
				placeholder: 'Add Field',
				displayOptions: {
					show: {
						operation: ['newEcommerceEvent'],
						resource: ['ecommerceEvents'],
					},
				},
				default: {},
				options: [
					{
						...appendLegalBaseOption,
						description:
							'Whether to include the phrase “This message was sent automatically with n8n” to the end of the message',
					},
				],
			},
		],
	};

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

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

		if (resource == 'ecommerceEvents' && operation == 'newEcommerceEvent') {
			const eventType = this.getNodeParameter('eventType', 0) as string;
			const eventFamily = EVENT_FAMILY;
			const event = ECOMMERCE_EVENT_TYPE_MAP[eventType];

			const additionalFields = this.getNodeParameter('additionalFields', 0) as IDataObject;
			const appendLegalBase = additionalFields.apppendLegalBase as boolean;

			const leadEmail = validateEmail(this, this.getNodeParameter('email', 0), 'Lead Email') as string;
			const leadName = (this.getNodeParameter('name', 0) as string).trim();
			const mobilePhone = (this.getNodeParameter('mobilePhone', 0 ) as string).trim();
			const personalPhone = (this.getNodeParameter('personalPhone', 0 ) as string).trim();
			const legalBases = LEGAL_BASES_OBJECT;

			let identifier;
			let specificPayload: any = {};

			const isCartAbandoned = eventType == 'ecommerceCartAbandoned';
			const isCheckoutStarted = eventType == 'ecommerceCheckoutStarted';
			const isOrderPlaced = eventType == 'ecommerceOrderPlaced';
			const isOrderPaid = eventType == 'ecommerceOrderPaid';
			const isOrderRefunded = eventType == 'ecommerceOrderRefunded';
			const isOrderCancelled = eventType == 'ecommerceOrderCancelled';
			const isOrderFulfilled = eventType == 'ecommerceOrderFulfilled';
			const isShipmentDelivered = eventType == 'ecommerceShipmentDelivered';

			const basePayload: IDataObject = {
				email: leadEmail,
				...(!isEmpty(leadName) && { name: leadName }),
				...(!isEmpty(mobilePhone) && { mobile_phone: mobilePhone }),
				...(!isEmpty(personalPhone) && { personal_phone: personalPhone }),
				...(appendLegalBase && { legal_bases: legalBases }),
			};

			if (
				isCartAbandoned ||
				isCheckoutStarted ||
				isOrderPlaced ||
				isOrderPaid ||
				isOrderRefunded
			) {
				let lineItems: any;
				let lineItemsBuilded: any;

				const currency = (this.getNodeParameter('currency', 0 ) as string).trim();
				const price = this.getNodeParameter('price', 0) as number;
				const totalItems = this.getNodeParameter('totalItems', 0) as number;

				if(!isOrderRefunded) {
					lineItems = this.getNodeParameter('lineItemsUi', 0);
					lineItemsBuilded = buildLineItems(lineItems);
					// console.info('lineItemsBuilded', lineItemsBuilded);
				}

				if (isCartAbandoned || isCheckoutStarted) {
					const checkoutUrl = (this.getNodeParameter('checkoutUrl', 0) as string).trim();

					specificPayload = {
						checkout_url: checkoutUrl,
						currency: currency,
						price: price,
						total_items: totalItems,
						line_items: lineItemsBuilded,
					};

					if(isCartAbandoned) {
						identifier = (this.getNodeParameter('identifierCartAbandoned', 0) as string).trim();
					} else if(isCheckoutStarted) {
						identifier = (this.getNodeParameter('identifierCheckoutStarted', 0) as string).trim();
					}

					specificPayload.identifier = identifier;
				}

				if (isOrderPlaced || isOrderPaid || isOrderRefunded) {
					identifier = (this.getNodeParameter('identifierOrder', 0) as string).trim();
					specificPayload = {
						currency: currency,
						price: price,
						total_items: totalItems,
						...(!isOrderRefunded && { line_items: lineItemsBuilded }),
					};

					if (isOrderPlaced || isOrderPaid) {
						const orderUrl = (this.getNodeParameter('orderUrl', 0) as string).trim();
						const shippingPrice = this.getNodeParameter('shippingPrice', 0) as number;
						const shippingCity = (this.getNodeParameter('shippingCity', 0) as string).trim();
						const shippingState = (this.getNodeParameter('shippingState', 0) as string).trim();
						const shippingCountry = (this.getNodeParameter('shippingCountry', 0) as string).trim();

						if(!isEmpty(orderUrl)) {
							specificPayload.order_url = orderUrl;
						}

						if(shippingPrice > 0) {
							specificPayload.shipping_price = shippingPrice;
						}

						if(!isEmpty(shippingCity)) {
							specificPayload.shipping_city = shippingCity;
						}

						if(!isEmpty(shippingState)) {
							specificPayload.shipping_state = shippingState;
						}

						if(!isEmpty(shippingCountry)) {
							specificPayload.shipping_country = shippingCountry;
						}
					}

					if(isOrderPlaced) {
						const cartIdentifier = (this.getNodeParameter('cartIdentifier', 0) as string).trim();
						const checkoutIdentifier = (this.getNodeParameter('checkoutIdentifier', 0) as string).trim();

						if(!isEmpty(cartIdentifier)) {
							specificPayload.cart_identifier = cartIdentifier;
						}

						if(!isEmpty(checkoutIdentifier)) {
							specificPayload.checkout_identifier = checkoutIdentifier;
						}
					}

					specificPayload.identifier = identifier;
				}
			}

			if (isOrderCancelled) {
				identifier = (this.getNodeParameter('identifierOrder', 0) as string).trim();
				const cancelReason = (this.getNodeParameter('cancelReason', 0) as string).trim();

				specificPayload = {
					identifier,
					...(!isEmpty(cancelReason) && { cancel_reason: cancelReason }),
				};
			}

			if (isOrderFulfilled || isShipmentDelivered) {
				identifier = (this.getNodeParameter('identifierShipment', 0) as string).trim();
				const orderIdentifier = (this.getNodeParameter('orderIdentifierExplicit', 0) as string).trim();

				if(isOrderFulfilled) {
					const trackingCompany = (this.getNodeParameter('trackingCompany', 0) as string).trim();
					const trackingCode = (this.getNodeParameter('trackingCode', 0) as string).trim();
					const trackingUrl = (this.getNodeParameter('trackingUrl', 0) as string).trim();

					specificPayload = {
						...(!isEmpty(trackingCompany) && { tracking_company: trackingCompany }),
						...(!isEmpty(trackingCode) && { tracking_code: trackingCode }),
						...(!isEmpty(trackingUrl) && { tracking_url: trackingUrl }),
					};
				}

				specificPayload.identifier = identifier;
				specificPayload.order_identifier = orderIdentifier;
			}

			const payload: IDataObject = {
				...basePayload,
				...specificPayload
			};

			const body: IDataObject = {
				event_type: event,
				event_family: eventFamily,
				payload: payload,
			};

			// console.info('body', body);
			responseData = await rdStationApiRequest.call(this, 'POST', `/events?event_type=${event}`, body);

			const executionData = this.helpers.constructExecutionMetaData(
				this.helpers.returnJsonArray(responseData as IDataObject),
				{ itemData: { item: 0 } },
			);
			returnData.push(...executionData);
		}

		return this.prepareOutputData(returnData);
	};
};
