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

test.describe(
	'NDV Paired Items',
	{
		annotation: [{ type: 'owner', description: 'Adore' }],
	},
	() => {
		test('maps paired input and output items', async ({ n8n }) => {
			await n8n.start.fromImportedWorkflow('multi-branch-data-transform.json');
			await n8n.canvas.clickZoomToFitButton();

			await n8n.workflowComposer.executeWorkflowAndWaitForNotification(
				'Workflow executed successfully',
			);

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

			await expect(n8n.ndv.inputPanel.get()).toContainText('6 items');
			await expect(n8n.ndv.outputPanel.get()).toContainText('6 items');

			await n8n.ndv.inputPanel.switchDisplayMode('table');
			await n8n.ndv.outputPanel.switchDisplayMode('table');

			// input to output
			const inputTableRow1 = n8n.ndv.inputPanel.getTableRow(1);
			await expect(inputTableRow1).toBeVisible();
			await expect(inputTableRow1).toHaveAttribute('data-test-id', 'hovering-item');

			// Move the cursor to simulate hover behavior
			await inputTableRow1.hover();
			await expect(n8n.ndv.outputPanel.getTableRow(4)).toHaveAttribute(
				'data-test-id',
				'hovering-item',
			);

			await n8n.ndv.inputPanel.getTableRow(2).hover();
			await expect(n8n.ndv.outputPanel.getTableRow(2)).toHaveAttribute(
				'data-test-id',
				'hovering-item',
			);

			await n8n.ndv.inputPanel.getTableRow(3).hover();
			await expect(n8n.ndv.outputPanel.getTableRow(6)).toHaveAttribute(
				'data-test-id',
				'hovering-item',
			);

			// output to input
			await n8n.ndv.outputPanel.getTableRow(1).hover();
			await expect(n8n.ndv.inputPanel.getTableRow(4)).toHaveAttribute(
				'data-test-id',
				'hovering-item',
			);

			await n8n.ndv.outputPanel.getTableRow(4).hover();
			await expect(n8n.ndv.inputPanel.getTableRow(1)).toHaveAttribute(
				'data-test-id',
				'hovering-item',
			);

			await n8n.ndv.outputPanel.getTableRow(2).hover();
			await expect(n8n.ndv.inputPanel.getTableRow(2)).toHaveAttribute(
				'data-test-id',
				'hovering-item',
			);

			await n8n.ndv.outputPanel.getTableRow(6).hover();
			await expect(n8n.ndv.inputPanel.getTableRow(3)).toHaveAttribute(
				'data-test-id',
				'hovering-item',
			);

			await n8n.ndv.outputPanel.getTableRow(1).hover();
			await expect(n8n.ndv.inputPanel.getTableRow(4)).toHaveAttribute(
				'data-test-id',
				'hovering-item',
			);
		});

		test('maps paired input and output items based on selected input node', async ({ n8n }) => {
			await n8n.start.fromImportedWorkflow('multi-branch-data-transform.json');
			await n8n.canvas.clickZoomToFitButton();
			await n8n.workflowComposer.executeWorkflowAndWaitForNotification(
				'Workflow executed successfully',
			);
			await n8n.canvas.openNode('Set2');

			await expect(n8n.ndv.inputPanel.get()).toContainText('6 items');
			await expect(n8n.ndv.outputPanel.getRunSelectorInput()).toHaveValue('2 of 2 (6 items)');

			await n8n.ndv.inputPanel.switchDisplayMode('table');
			await n8n.ndv.outputPanel.switchDisplayMode('table');

			// Default hover state should have first item from input node highlighted
			const hoveringItem = n8n.page.locator('[data-test-id="hovering-item"]');
			await expect(hoveringItem).toContainText('1111');
			await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('1111');

			// Select different input node and check that the hover state is updated
			await n8n.ndv.inputPanel.getNodeInputOptions().click();
			await n8n.page.getByRole('option', { name: 'Set1' }).click();
			await expect(hoveringItem).toContainText('1000');

			// Hover on input item and verify output hover state
			await n8n.ndv.inputPanel.getTable().locator('text=1000').hover();
			await expect(
				n8n.ndv.outputPanel.get().locator('[data-test-id="hovering-item"]'),
			).toContainText('1000');
			await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('1000');

			// Switch back to Sort input
			await n8n.ndv.inputPanel.getNodeInputOptions().click();
			await n8n.page.getByRole('option', { name: 'Sort' }).click();
			await n8n.ndv.changeOutputRunSelector('1 of 2 (6 items)');

			await expect(hoveringItem).toContainText('1111');
			await n8n.ndv.inputPanel.getTable().locator('text=1111').hover();
			await expect(
				n8n.ndv.outputPanel.get().locator('[data-test-id="hovering-item"]'),
			).toContainText('1111');
			await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('1111');
		});

		test('maps paired input and output items based on selected run', async ({ n8n }) => {
			await n8n.start.fromImportedWorkflow('multi-branch-data-transform.json');
			await n8n.canvas.clickZoomToFitButton();
			await n8n.workflowComposer.executeWorkflowAndWaitForNotification(
				'Workflow executed successfully',
			);
			await n8n.canvas.openNode('Set3');

			await n8n.ndv.inputPanel.switchDisplayMode('table');
			await n8n.ndv.outputPanel.switchDisplayMode('table');

			// Start from linked state
			await n8n.ndv.ensureOutputRunLinking(true);
			await n8n.ndv.inputPanel.getTbodyCell(0, 0).click(); // remove tooltip

			await expect(n8n.ndv.inputPanel.getRunSelectorInput()).toHaveValue('2 of 2 (6 items)');
			await expect(n8n.ndv.outputPanel.getRunSelectorInput()).toHaveValue('2 of 2 (6 items)');

			await n8n.ndv.changeOutputRunSelector('1 of 2 (6 items)');
			await expect(n8n.ndv.inputPanel.getRunSelectorInput()).toHaveValue('1 of 2 (6 items)');
			await expect(n8n.ndv.outputPanel.getRunSelectorInput()).toHaveValue('1 of 2 (6 items)');

			await expect(n8n.ndv.inputPanel.getTableRow(1)).toContainText('1111');
			await expect(n8n.ndv.inputPanel.getTableRow(1)).toHaveAttribute(
				'data-test-id',
				'hovering-item',
			);

			await expect(n8n.ndv.outputPanel.getTableRow(1)).toContainText('1111');
			await n8n.ndv.outputPanel.getTableRow(1).hover();

			await expect(n8n.ndv.outputPanel.getTableRow(3)).toContainText('4444');
			await n8n.ndv.outputPanel.getTableRow(3).hover();

			await expect(n8n.ndv.inputPanel.getTableRow(3)).toContainText('4444');
			await expect(n8n.ndv.inputPanel.getTableRow(3)).toHaveAttribute(
				'data-test-id',
				'hovering-item',
			);

			await n8n.ndv.changeOutputRunSelector('2 of 2 (6 items)');

			await expect(n8n.ndv.inputPanel.getTableRow(1)).toContainText('1000');
			await n8n.ndv.inputPanel.getTableRow(1).hover();

			await expect(n8n.ndv.outputPanel.getTableRow(1)).toContainText('1000');
			await expect(n8n.ndv.outputPanel.getTableRow(1)).toHaveAttribute(
				'data-test-id',
				'hovering-item',
			);

			await expect(n8n.ndv.outputPanel.getTableRow(3)).toContainText('2000');
			await n8n.ndv.outputPanel.getTableRow(3).hover();

			await expect(n8n.ndv.inputPanel.getTableRow(3)).toContainText('2000');
			await expect(n8n.ndv.inputPanel.getTableRow(3)).toHaveAttribute(
				'data-test-id',
				'hovering-item',
			);
		});

		test('can pair items between input and output across branches and runs', async ({ n8n }) => {
			await n8n.start.fromImportedWorkflow('multi-branch-data-transform.json');
			await n8n.canvas.clickZoomToFitButton();
			await n8n.workflowComposer.executeWorkflowAndWaitForNotification(
				'Workflow executed successfully',
			);
			await n8n.canvas.openNode('IF');

			await n8n.ndv.inputPanel.switchDisplayMode('table');
			await n8n.ndv.outputPanel.switchDisplayMode('table');

			// Switch to False Branch
			await n8n.ndv.outputPanel.get().getByText('False Branch (2 items)').click();
			await expect(n8n.ndv.outputPanel.getTableRow(1)).toContainText('8888');
			await n8n.ndv.outputPanel.getTableRow(1).hover();

			await expect(n8n.ndv.inputPanel.getTableRow(5)).toContainText('8888');
			await expect(n8n.ndv.inputPanel.getTableRow(5)).toHaveAttribute(
				'data-test-id',
				'hovering-item',
			);

			await expect(n8n.ndv.outputPanel.getTableRow(2)).toContainText('9999');
			await n8n.ndv.outputPanel.getTableRow(2).hover();

			await expect(n8n.ndv.inputPanel.getTableRow(6)).toContainText('9999');
			await expect(n8n.ndv.inputPanel.getTableRow(6)).toHaveAttribute(
				'data-test-id',
				'hovering-item',
			);

			await n8n.ndv.close();

			await n8n.canvas.openNode('Set5');

			// Switch to True Branch for input
			await n8n.ndv.inputPanel.get().getByText('True Branch').click();

			await n8n.ndv.changeOutputRunSelector('(2 items)');
			await expect(n8n.ndv.outputPanel.getTableRow(1)).toContainText('8888');
			await n8n.ndv.outputPanel.getTableRow(1).hover();

			// Should not have matching hover state when branches don't match
			const hoveringItems = n8n.ndv.inputPanel.get().locator('[data-test-id="hovering-item"]');
			await expect(hoveringItems).toHaveCount(0);

			await expect(n8n.ndv.inputPanel.getTableRow(1)).toContainText('1111');
			await n8n.ndv.inputPanel.getTableRow(1).hover();
			const outputHoveringItems = n8n.ndv.outputPanel.getHoveringItems();
			await expect(outputHoveringItems).toHaveCount(0);

			// Switch to False Branch
			await n8n.ndv.inputPanel.get().getByText('False Branch').click();
			await expect(n8n.ndv.inputPanel.getTableRow(1)).toContainText('8888');
			await n8n.ndv.inputPanel.getTableRow(1).hover();

			await n8n.ndv.changeOutputRunSelector('(4 items)');
			await expect(n8n.ndv.outputPanel.getTableRow(1)).toContainText('1111');
			await n8n.ndv.outputPanel.getTableRow(1).hover();

			await n8n.ndv.changeOutputRunSelector('(2 items)');
			await expect(n8n.ndv.inputPanel.getTableRow(1)).toContainText('8888');
			await n8n.ndv.inputPanel.getTableRow(1).hover();
			await expect(
				n8n.ndv.outputPanel.get().locator('[data-test-id="hovering-item"]'),
			).toContainText('8888');
		});

		test('should auto-fix pairedItem when multiple inputs create single output', async ({
			n8n,
		}) => {
			await n8n.start.fromImportedWorkflow('Test_workflow_ndv_paired_item_single_output.json');
			await n8n.canvas.openNode('Use paired item');
			await n8n.ndv.execute();

			await expect(n8n.ndv.getNodeRunErrorMessage()).toBeHidden();
			await expect(n8n.ndv.outputPanel.get()).toContainText('Jay Gatsby');
		});

		test('can resolve expression with paired item in multi-input node', async ({ n8n }) => {
			await n8n.start.fromImportedWorkflow('expression_with_paired_item_in_multi_input_node.json');

			await n8n.canvas.clickZoomToFitButton();

			const PINNED_DATA = [
				{
					id: 'abc',
					historyId: 'def',
					messages: [
						{
							id: 'abc',
						},
					],
				},
				{
					id: 'abc',
					historyId: 'def',
					messages: [
						{
							id: 'abc',
						},
						{
							id: 'abc',
						},
						{
							id: 'abc',
						},
					],
				},
				{
					id: 'abc',
					historyId: 'def',
					messages: [
						{
							id: 'abc',
						},
					],
				},
			];

			await n8n.canvas.openNode('Get thread details1');
			await n8n.ndv.setPinnedData(PINNED_DATA);
			await n8n.ndv.close();

			await n8n.workflowComposer.executeWorkflowAndWaitForNotification(
				'Workflow executed successfully',
			);
			await n8n.canvas.openNode('Switch1');
			await n8n.ndv.execute();

			await expect(n8n.ndv.getParameterExpressionPreviewOutput()).toContainText('1');

			await n8n.ndv.getInlineExpressionEditorInput().click();
			await expect(n8n.ndv.getInlineExpressionEditorPreview()).toContainText('1');

			// Select next item
			await n8n.ndv.expressionSelectNextItem();
			await expect(n8n.ndv.getInlineExpressionEditorPreview()).toContainText('3');

			// Select next item again
			await n8n.ndv.expressionSelectNextItem();
			await expect(n8n.ndv.getInlineExpressionEditorPreview()).toContainText('1');

			// Next button should be disabled
			await expect(n8n.ndv.getInlineExpressionEditorItemNextButton()).toBeDisabled();
		});
	},
);
