import { nanoid } from 'nanoid';

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

const TEST_API_KEY = 'test-api-key';

test.describe(
	'Access Control Boundaries',
	{
		annotation: [{ type: 'owner', description: 'Identity & Access' }],
	},
	() => {
		test('should prevent credential editing by sharee', async ({ n8n, api }) => {
			const member = await api.publicApi.createUser({
				email: `member-${nanoid()}@test.com`,
				firstName: 'Test',
				lastName: 'Member',
			});

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

			const memberApi = await api.createApiForUser(member);
			const memberProject = await memberApi.projects.getMyPersonalProject();
			await api.credentials.shareCredential(credential.id, [memberProject.id]);

			const memberN8n = await n8n.start.withUser(member);
			await memberN8n.navigate.toCredentials();
			await memberN8n.credentials.cards.clickCredentialCard(credentialName);

			await expect(memberN8n.credentials.credentialModal.getCredentialName()).toContainText(
				credentialName,
			);
			await expect(memberN8n.credentials.credentialModal.getSaveButton()).toBeHidden();
		});

		test('should allow admin full access to credentials created by others', async ({
			n8n,
			api,
		}) => {
			const member = await api.publicApi.createUser({
				email: `member-${nanoid()}@test.com`,
				firstName: 'Test',
				lastName: 'Member',
			});
			const admin = await api.publicApi.createUser({
				email: `admin-${nanoid()}@test.com`,
				firstName: 'Test',
				lastName: 'Admin',
				role: 'global:admin',
			});

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

			const adminN8n = await n8n.start.withUser(admin);
			await adminN8n.navigate.toCredentials();
			await adminN8n.credentials.cards.clickCredentialCard(credentialName);

			await expect(adminN8n.credentials.credentialModal.getCredentialName()).toContainText(
				credentialName,
			);

			const apiKeyInput = adminN8n.credentials.credentialModal.getFieldInput('apiKey');
			await expect(apiKeyInput).toHaveValue(/__n8n_BLANK_VALUE_/);

			await adminN8n.credentials.credentialModal.changeTab('Sharing');
			await expect(adminN8n.credentials.credentialModal.getUsersSelect()).toBeVisible();

			await adminN8n.credentials.credentialModal.getUsersSelect().click();
			// Personal projects show "Name (Personal space)" instead of email
			const adminName = `${admin.firstName} ${admin.lastName}`;
			await expect(
				adminN8n.credentials.credentialModal.getVisibleDropdown().getByText(adminName),
			).toBeVisible();
		});

		test('should prevent access to private workflows via direct URL', async ({ api }) => {
			const member = await api.publicApi.createUser({
				email: `member-${nanoid()}@test.com`,
				firstName: 'Test',
				lastName: 'Member',
			});
			const workflow = await api.workflows.createWorkflow({
				name: `Private 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 response = await memberApi.request.get(`/rest/workflows/${workflow.id}`);
			expect(response.status()).toBe(403);
		});

		test('should enforce project isolation for team projects', async ({ n8n, api }) => {
			await api.setMaxTeamProjectsQuota(-1);

			const devProject = await api.projects.createProject(`Development ${nanoid()}`);
			const testProject = await api.projects.createProject(`Testing ${nanoid()}`);

			const devCredName = `Dev Credential ${nanoid()}`;
			await api.credentials.createCredential({
				name: devCredName,
				type: 'notionApi',
				data: { apiKey: TEST_API_KEY },
				projectId: devProject.id,
			});

			const testCredName = `Test Credential ${nanoid()}`;
			await api.credentials.createCredential({
				name: testCredName,
				type: 'notionApi',
				data: { apiKey: TEST_API_KEY },
				projectId: testProject.id,
			});

			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();

			await n8n.ndv.getNodeCredentialsSelect().click();
			const credentialDropdown = n8n.ndv.getVisiblePopper();
			await expect(credentialDropdown.getByText(testCredName)).toBeVisible();
			await expect(credentialDropdown.getByText(devCredName)).toBeHidden();
		});

		test('should prevent sharing team project workflows', async ({ n8n, api }) => {
			const teamProject = await api.projects.createProject(`Team Project ${nanoid()}`);
			const teamWorkflow = await api.workflows.createInProject(teamProject.id, {
				name: `Team Workflow ${nanoid()}`,
			});

			await n8n.navigate.toWorkflow(teamWorkflow.id);
			await n8n.canvas.openShareModal();

			// Team project workflows cannot be shared - no user selector shown
			await expect(n8n.workflowSharingModal.getUsersSelect()).toBeHidden();
		});
	},
);
