import { nanoid } from 'nanoid';

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

const TEST_API_KEY = 'test-api-key';

test.describe(
	'Credential Visibility Rules',
	{
		annotation: [{ type: 'owner', description: 'Identity & Access' }],
	},
	() => {
		test('should only show credentials from the same team project', async ({ n8n, api }) => {
			await n8n.navigate.toCredentials();
			const personalCredName = `Personal Credential ${nanoid()}`;
			await n8n.credentialsComposer.createFromList(
				'Notion API',
				{ apiKey: TEST_API_KEY },
				{
					name: personalCredName,
				},
			);

			const devProject = await n8n.projectComposer.createProject(`Development ${nanoid()}`);
			await n8n.projectTabs.clickCredentialsTab();
			const devCredName = `Dev Credential ${nanoid()}`;
			await n8n.credentialsComposer.createFromList(
				'Notion API',
				{ apiKey: TEST_API_KEY },
				{ projectId: devProject.projectId, name: devCredName },
			);

			const testProject = await api.projects.createProject(`Test ${nanoid()}`);
			await n8n.navigate.toProject(testProject.id);
			await n8n.projectTabs.clickCredentialsTab();
			const testCredName = `Test Credential ${nanoid()}`;
			await n8n.credentialsComposer.createFromList(
				'Notion API',
				{ apiKey: TEST_API_KEY },
				{ projectId: testProject.id, name: testCredName },
			);

			await n8n.navigate.toProject(testProject.id);
			await n8n.projectTabs.clickWorkflowsTab();
			await n8n.workflows.clickNewWorkflowButtonFromProject();
			await n8n.canvas.addNode('Manual Trigger');
			await n8n.canvas.addNode('Notion');
			await n8n.canvas.getFirstAction().click();

			// Only test project credential should be visible
			await n8n.ndv.getNodeCredentialsSelect().click();
			const credentialDropdown = n8n.ndv.getVisiblePopper();
			await expect(credentialDropdown.getByText(testCredName)).toBeVisible();
			await expect(credentialDropdown.getByText(personalCredName)).toBeHidden();
			await expect(credentialDropdown.getByText(devCredName)).toBeHidden();
		});

		test('should show personal and shared credentials for members', async ({ n8n, api }) => {
			const member = await api.publicApi.createUser({
				email: `member-${nanoid()}@test.com`,
				firstName: 'Test',
				lastName: 'Member',
			});

			const ownerCredName = `Owner Credential ${nanoid()}`;
			await n8n.navigate.toCredentials();
			await n8n.credentials.addResource.credential();
			await n8n.credentials.selectCredentialType('Notion API');
			await n8n.credentials.credentialModal.fillField('apiKey', TEST_API_KEY);
			await n8n.credentials.credentialModal.renameCredential(ownerCredName);
			await n8n.credentials.credentialModal.save();

			await n8n.credentials.credentialModal.changeTab('Sharing');
			await n8n.credentials.credentialModal.addUserToSharing(member.email);
			await n8n.credentials.credentialModal.saveSharing();
			await n8n.credentials.credentialModal.close();

			const memberN8n = await n8n.start.withUser(member);
			await memberN8n.navigate.toCredentials();
			const memberCredName = `Member Credential ${nanoid()}`;
			await memberN8n.credentialsComposer.createFromList(
				'Notion API',
				{ apiKey: TEST_API_KEY },
				{
					name: memberCredName,
				},
			);

			await memberN8n.navigate.toWorkflow('new');
			await memberN8n.canvas.addNode('Manual Trigger');
			await memberN8n.canvas.addNode('Notion');
			await memberN8n.canvas.getFirstAction().click();

			// Both own credential and shared credential should be visible
			await memberN8n.ndv.getNodeCredentialsSelect().click();
			const credentialDropdown = memberN8n.ndv.getVisiblePopper();
			await expect(credentialDropdown.getByText(ownerCredName)).toBeVisible();
			await expect(credentialDropdown.getByText(memberCredName)).toBeVisible();
		});

		test('should only show own credentials in shared workflow for members', async ({
			n8n,
			api,
		}) => {
			const member = await api.publicApi.createUser({
				email: `member-${nanoid()}@test.com`,
				firstName: 'Test',
				lastName: 'Member',
			});

			const ownerCredName = `Owner Credential ${nanoid()}`;
			await n8n.navigate.toCredentials();
			await n8n.credentialsComposer.createFromList(
				'Notion API',
				{ apiKey: TEST_API_KEY },
				{ name: ownerCredName },
			);

			const workflow = await api.workflows.createWorkflow({
				name: `Test Workflow ${nanoid()}`,
				nodes: [
					{
						id: 'manual-trigger',
						name: 'Manual Trigger',
						type: 'n8n-nodes-base.manualTrigger',
						position: [100, 200],
						parameters: {},
						typeVersion: 1,
					},
				],
				connections: {},
			});

			const memberApi = await api.createApiForUser(member);
			const memberProject = await memberApi.projects.getMyPersonalProject();
			await api.workflows.shareWorkflow(workflow.id, [memberProject.id]);

			const memberN8n = await n8n.start.withUser(member);
			await memberN8n.navigate.toCredentials();
			const memberCredName = `Member Credential ${nanoid()}`;
			await memberN8n.credentialsComposer.createFromList(
				'Notion API',
				{ apiKey: TEST_API_KEY },
				{
					name: memberCredName,
				},
			);

			await memberN8n.navigate.toWorkflow(workflow.id);
			await expect(memberN8n.canvas.getCanvasNodes().first()).toBeVisible();

			await memberN8n.canvas.addNode('Notion');
			await memberN8n.canvas.getFirstAction().click();

			// Member should see their own credential but NOT the owner's unshared credential
			await memberN8n.ndv.getNodeCredentialsSelect().click();
			const credentialDropdown = memberN8n.ndv.getVisiblePopper();
			await expect(credentialDropdown.getByText(memberCredName)).toBeVisible();
			await expect(credentialDropdown.getByText(ownerCredName)).toBeHidden();
		});

		test('should show owner and workflow creator credentials for global owner in shared workflows', async ({
			n8n,
			api,
		}) => {
			const member = await api.publicApi.createUser({
				email: `member-${nanoid()}@test.com`,
				firstName: 'Test',
				lastName: 'Member',
			});

			const memberApi = await api.createApiForUser(member);
			const memberCredName = `Member Credential ${nanoid()}`;
			await memberApi.credentials.createCredential({
				name: memberCredName,
				type: 'notionApi',
				data: { apiKey: TEST_API_KEY },
			});

			const workflow = await memberApi.workflows.createWorkflow({
				name: `Test Workflow ${nanoid()}`,
				nodes: [
					{
						id: 'manual-trigger',
						name: 'Manual Trigger',
						type: 'n8n-nodes-base.manualTrigger',
						position: [100, 200],
						parameters: {},
						typeVersion: 1,
					},
				],
				connections: {},
			});

			const ownerProject = await api.projects.getMyPersonalProject();
			await memberApi.workflows.shareWorkflow(workflow.id, [ownerProject.id]);

			const ownerCredName = `Owner Credential ${nanoid()}`;
			await api.credentials.createCredential({
				name: ownerCredName,
				type: 'notionApi',
				data: { apiKey: TEST_API_KEY },
			});

			await n8n.navigate.toWorkflow(workflow.id);
			await expect(n8n.canvas.getCanvasNodes().first()).toBeVisible();

			await n8n.canvas.addNode('Notion');
			await n8n.canvas.getFirstAction().click();

			// Global owner should see both their own credential and the workflow creator's credential
			await n8n.ndv.getNodeCredentialsSelect().click();
			const credentialOptions = n8n.ndv.getVisiblePopper().locator('li');
			await expect(credentialOptions.filter({ hasText: ownerCredName })).toBeVisible();
			await expect(credentialOptions.filter({ hasText: memberCredName })).toBeVisible();
		});

		test('should show all personal credentials for global owner in own workflows', async ({
			n8n,
			api,
		}) => {
			const member = await api.publicApi.createUser({
				email: `member-${nanoid()}@test.com`,
				firstName: 'Test',
				lastName: 'Member',
			});

			const memberApi = await api.createApiForUser(member);
			const memberCredName = `Member Credential ${nanoid()}`;
			await memberApi.credentials.createCredential({
				name: memberCredName,
				type: 'notionApi',
				data: { apiKey: TEST_API_KEY },
			});

			await n8n.navigate.toWorkflow('new');
			await n8n.canvas.addNode('Manual Trigger');
			await n8n.canvas.addNode('Notion');
			await n8n.canvas.getFirstAction().click();

			// Owner should see member's credential (global owner privilege)
			await n8n.ndv.getNodeCredentialsSelect().click();
			const credentialOptions = n8n.ndv.getVisiblePopper().locator('li');
			await expect(credentialOptions.filter({ hasText: memberCredName })).toBeVisible();
		});
	},
);
