import { test, expect } from '../../../../../fixtures/base';

test.describe('Data Mapping', () => {
	test.describe
		.serial('Expression Preview', () => {
			test('maps expressions from table json, and resolves value based on hover', async ({
				n8n,
			}) => {
				// This test is marked as serial because hover/tooltips are unreliable when running in parallel against a single server due to resource contention.

				await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
				await n8n.canvas.openNode('Set');
				await n8n.ndv.inputPanel.switchDisplayMode('table');

				await expect(n8n.ndv.inputPanel.getTable()).toBeVisible();

				await expect(n8n.ndv.getParameterInputField('name')).toHaveValue('other');
				await expect(n8n.ndv.getParameterInputField('value')).toHaveValue('');

				const countCell = n8n.ndv.inputPanel.getTableCellSpan(0, 0, 'count');
				await expect(countCell).toBeVisible();

				const valueParameter = n8n.ndv.getParameterInput('value');
				await n8n.interactions.precisionDragToTarget(countCell, valueParameter, 'bottom');

				await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
					'{{ $json.input[0].count }}',
				);
				await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('0');

				await n8n.ndv.inputPanel.getTbodyCell(0, 0).hover();
				await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('0');

				await n8n.ndv.inputPanel.getTbodyCell(1, 0).hover();
				await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('1');

				await n8n.ndv.execute();

				await expect(n8n.ndv.outputPanel.getTable()).toBeVisible();

				await n8n.ndv.outputPanel.getTbodyCell(0, 0).hover();
				await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('0');

				await n8n.ndv.outputPanel.getTbodyCell(1, 0).hover();
				await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('1');
			});
		});
	test('maps expressions from json view', async ({ n8n }) => {
		await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
		await n8n.canvas.openNode('Set');
		await n8n.ndv.inputPanel.switchDisplayMode('json');

		const expectedJsonText =
			'[  {    "input": [      {        "count": 0,        "with space": "!!",        "with.dot": "!!",        "with"quotes": "!!"      }    ]  },  {    "input": [      {        "count": 1      }    ]  }]';
		await expect(async () => {
			await expect(n8n.ndv.inputPanel.get().getByText(expectedJsonText)).toBeVisible();
		}).toPass({ timeout: 1000 });

		await expect(n8n.ndv.inputPanel.getJsonDataContainer()).toBeVisible();

		const inputSpan = n8n.ndv.inputPanel.getJsonProperty('input');
		await expect(inputSpan).toBeVisible();

		const valueParameterInput = n8n.ndv.getParameterInput('value');
		await expect(valueParameterInput).toBeVisible();

		await inputSpan.dragTo(valueParameterInput);

		const expressionEditor = n8n.ndv.getInlineExpressionEditorInput();
		await expect(expressionEditor).toBeVisible();
		await expect(expressionEditor).toHaveText('{{ $json.input }}');

		await n8n.page.keyboard.press('Escape');

		await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('Array:');
		await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('"count": 0');

		const countSpan = n8n.ndv.inputPanel.getJsonPropertyContaining('count');
		await expect(countSpan).toBeVisible();

		await n8n.interactions.precisionDragToTarget(
			countSpan,
			n8n.ndv.getInlineExpressionEditorInput(),
			'bottom',
		);

		await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
			'{{ $json.input }}{{ $json.input[0].count }}',
		);

		await n8n.page.keyboard.press('Escape');

		const previewElement = n8n.ndv.getParameterExpressionPreviewValue();
		await expect(previewElement).toBeVisible();
	});

	test('maps expressions from previous nodes', async ({ n8n }) => {
		await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
		await n8n.canvas.openNode('Set1');
		await n8n.ndv.executePrevious();

		const scheduleNode = n8n.ndv.inputPanel.get().getByText('Schedule Trigger');
		await expect(scheduleNode).toBeVisible();
		await scheduleNode.click();

		const schemaItem = n8n.ndv.inputPanel.getSchemaItemText('count');
		await expect(schemaItem).toBeVisible();

		const valueParameterInput = n8n.ndv.getParameterInput('value');
		await expect(valueParameterInput).toBeVisible();

		await n8n.interactions.precisionDragToTarget(
			schemaItem.locator('span'),
			valueParameterInput,
			'top',
		);

		await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
			"{{ $('Schedule Trigger').item.json.input[0].count }}",
		);

		await n8n.page.keyboard.press('Escape');

		await n8n.ndv.inputPanel.switchDisplayMode('table');
		await n8n.ndv.selectInputNode('Schedule Trigger');

		const headerElement = n8n.ndv.inputPanel.getTableHeader(0);
		await expect(headerElement).toBeVisible();

		await n8n.interactions.precisionDragToTarget(
			headerElement,
			n8n.ndv.getInlineExpressionEditorInput(),
			'top',
		);

		await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
			"{{ $('Schedule Trigger').item.json.input }}{{ $('Schedule Trigger').item.json.input[0].count }}",
		);

		await n8n.ndv.selectInputNode('Set');
	});
	test('maps expressions from table header', async ({ n8n }) => {
		await n8n.start.fromImportedWorkflow('Test_workflow-actions_paste-data.json');
		await n8n.canvas.openNode('Set');
		await n8n.ndv.executePrevious();
		await n8n.ndv.inputPanel.switchDisplayMode('table');

		await expect(n8n.ndv.inputPanel.getTable()).toBeVisible();

		const addValueButton = n8n.ndv.getAddValueButton();
		await expect(addValueButton).toBeVisible();
		await addValueButton.click();

		await n8n.page.getByRole('option', { name: 'String' }).click();

		await expect(n8n.ndv.getParameterInputField('name')).toHaveValue('propertyName');
		await expect(n8n.ndv.getParameterInputField('value')).toHaveValue('');

		const firstHeader = n8n.ndv.inputPanel.getTableHeader(0);
		await expect(firstHeader).toBeVisible();

		const valueParameter = n8n.ndv.getParameterInput('value');
		await n8n.interactions.precisionDragToTarget(firstHeader, valueParameter, 'bottom');

		await expect(n8n.ndv.getInlineExpressionEditorInput()).toBeVisible();
		await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText('{{ $json.timestamp }}');

		await n8n.page.keyboard.press('Escape');

		const currentYear = new Date().getFullYear().toString();
		await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText(currentYear);

		const secondHeader = n8n.ndv.inputPanel.getTableHeader(1);
		await expect(secondHeader).toBeVisible();

		await n8n.interactions.precisionDragToTarget(
			secondHeader,
			n8n.ndv.getInlineExpressionEditorInput(),
			'top',
		);

		await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
			"{{ $json['Readable date'] }}{{ $json.timestamp }}",
		);
	});

	test('maps expressions from schema view', async ({ n8n }) => {
		await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
		await n8n.canvas.openNode('Set');

		await n8n.ndv.getParameterInputField('value').clear();
		await n8n.page.keyboard.press('Escape');

		const countSchemaItem = n8n.ndv.inputPanel.getSchemaItemText('count');
		await expect(countSchemaItem).toBeVisible();

		const valueParameter = n8n.ndv.getParameterInput('value');
		await n8n.interactions.precisionDragToTarget(countSchemaItem, valueParameter, 'bottom');

		await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText('{{ $json.input[0].count }}');
		await n8n.page.keyboard.press('Escape');
		await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('0');

		const inputSchemaItem = n8n.ndv.inputPanel.getSchemaItemText('input');
		await expect(inputSchemaItem).toBeVisible();

		await n8n.interactions.precisionDragToTarget(inputSchemaItem, valueParameter, 'top');

		await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
			'{{ $json.input }}{{ $json.input[0].count }}',
		);
		await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('[object Object]0');
	});

	test('maps keys to path', async ({ n8n }) => {
		await n8n.start.fromBlankCanvas();
		await n8n.canvas.addNode('Manual Trigger');
		await n8n.canvas.openNode('When clicking ‘Execute workflow’');

		await n8n.ndv.setPinnedData([
			{
				input: [
					{
						'hello.world': {
							'my count': 0,
						},
					},
				],
			},
			{
				input: [
					{
						'hello.world': {
							'my count': 1,
						},
					},
				],
			},
		]);

		await n8n.ndv.close();

		await n8n.canvas.addNode('Sort');

		const addFieldButton = n8n.ndv.getAddFieldToSortByButton();
		await addFieldButton.click();

		const myCountSpan = n8n.ndv.inputPanel.getSchemaItemText('my count');
		await expect(myCountSpan).toBeVisible();

		const fieldNameParameter = n8n.ndv.getParameterInput('fieldName');
		await n8n.interactions.precisionDragToTarget(myCountSpan, fieldNameParameter, 'bottom');

		await expect(n8n.ndv.getInlineExpressionEditorInput()).toBeHidden();
		await expect(n8n.ndv.getParameterInputField('fieldName')).toHaveValue(
			"input[0]['hello.world']['my count']",
		);
	});

	// There is an issue here sometimes, when dragging to the target it prepends the last value that was in the window even if it was cleared
	test.fixme('maps expressions to updated fields correctly @fixme', async ({ n8n }) => {
		await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
		await n8n.canvas.openNode('Set');

		await n8n.ndv.fillParameterInputByName('value', 'delete me');
		await n8n.ndv.fillParameterInputByName('name', 'test');
		await n8n.ndv.getParameterInputField('name').blur();

		await n8n.ndv.fillParameterInputByName('value', 'fun');
		await n8n.ndv.getParameterInputField('value').clear();

		const countSchemaItem = n8n.ndv.inputPanel.getSchemaItemText('count');
		await expect(countSchemaItem).toBeVisible();

		const valueParameter = n8n.ndv.getParameterInput('value');
		await n8n.interactions.precisionDragToTarget(countSchemaItem, valueParameter, 'bottom');

		await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText('{{ $json.input[0].count }}');
		await n8n.page.keyboard.press('Escape');
		await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('0');

		const inputSchemaItem = n8n.ndv.inputPanel.getSchemaItemText('input');
		await expect(inputSchemaItem).toBeVisible();

		await n8n.interactions.precisionDragToTarget(inputSchemaItem, valueParameter, 'top');

		await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
			'{{ $json.input }}{{ $json.input[0].count }}',
		);
		await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('[object Object]0');
	});

	test('renders expression preview when a previous node is selected', async ({ n8n }) => {
		await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
		await n8n.canvas.openNode('Set');

		await n8n.ndv.fillParameterInputByName('value', 'test_value');
		await n8n.ndv.fillParameterInputByName('name', 'test_name');
		await n8n.ndv.close();

		await n8n.canvas.openNode('Set1');
		await n8n.ndv.executePrevious();
		await n8n.ndv.inputPanel.switchDisplayMode('table');

		const firstHeader = n8n.ndv.inputPanel.getTableHeader(0);
		await expect(firstHeader).toBeVisible();

		const valueParameter = n8n.ndv.getParameterInput('value');
		await n8n.interactions.precisionDragToTarget(firstHeader, valueParameter, 'bottom');

		await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('test_value');

		await n8n.ndv.selectInputNode('Schedule Trigger');
		await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('test_value');
	});

	test('shows you can drop to inputs, including booleans', async ({ n8n }) => {
		await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
		await n8n.canvas.openNode('Set');

		await expect(n8n.ndv.getParameterSwitch('includeOtherFields')).toBeVisible();
		await expect(n8n.ndv.getParameterTextInput('includeOtherFields')).toBeHidden();

		const countSpan = n8n.ndv.inputPanel.getSchemaItemText('count');
		await expect(countSpan).toBeVisible();

		await countSpan.hover();
		await n8n.page.mouse.down();
		await n8n.page.mouse.move(100, 100);

		await expect(n8n.ndv.getParameterSwitch('includeOtherFields')).toBeHidden();
		await expect(n8n.ndv.getParameterTextInput('includeOtherFields')).toBeVisible();

		const includeOtherFieldsInput = n8n.ndv.getParameterTextInput('includeOtherFields');
		await expect(includeOtherFieldsInput).toHaveCSS('outline', /rgb\(90, 76, 194\) dashed/);

		const valueInput = n8n.ndv.getParameterTextInput('value');
		await expect(valueInput).toHaveCSS('outline', /rgb\(90, 76, 194\) dashed/);

		await n8n.page.mouse.up();
	});

	test('maps expressions to a specific location in the editor', async ({ n8n }) => {
		await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
		await n8n.canvas.openNode('Set');

		await n8n.ndv.fillParameterInputByName('value', '=');
		await n8n.ndv.getInlineExpressionEditorContent().fill('hello world\n\nnewline');
		await n8n.page.keyboard.press('Escape');

		const countSchemaItem = n8n.ndv.inputPanel.getSchemaItemText('count');
		await expect(countSchemaItem).toBeVisible();

		const valueParameter = n8n.ndv.getParameterInput('value');
		await n8n.interactions.precisionDragToTarget(countSchemaItem, valueParameter, 'top');

		await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
			'{{ $json.input[0].count }}hello worldnewline',
		);
		await n8n.page.keyboard.press('Escape');
		await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText(
			'0hello world\n\nnewline',
		);

		const inputSchemaItem = n8n.ndv.inputPanel.getSchemaItemText('input');
		await expect(inputSchemaItem).toBeVisible();

		await n8n.interactions.precisionDragToTarget(inputSchemaItem, valueParameter, 'center');

		await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
			'{{ $json.input[0].count }}hello world{{ $json.input }}newline',
		);
	});
});
