import test, { expect, type Page } from '@playwright/test';
import { cleanupBackend, cleanupScimServiceProvider } from 'utils/cleanup.util';
import { oidcClients, userGroups, users } from '../data';

async function configureOidcClient(page: Page) {
	await page.goto(`/settings/admin/oidc-clients/${oidcClients.scim.id}`);

	await page.getByRole('tab', { name: 'SCIM Provisioning' }).click();

	await page
		.getByLabel('SCIM Endpoint')
		.fill(process.env.SCIM_SERVICE_PROVIDER_URL_INTERNAL || 'http://scim.provider/api');

	await page.getByRole('button', { name: 'Enable' }).click();
}

async function syncScimServiceProvider(page: Page) {
	await page.goto(`/settings/admin/oidc-clients/${oidcClients.scim.id}`);
	await page.getByRole('tab', { name: 'SCIM Provisioning' }).click();

	await page.getByRole('button', { name: 'Sync now' }).click();
	await page.waitForSelector('[data-type="success"]');
}

test.beforeEach(async () => {
	await cleanupBackend({ skipLdapSetup: true });
});

test.describe('SCIM Configuration', () => {
	test('Enable SCIM for OIDC client', async ({ page }) => {
		await page.goto(`/settings/admin/oidc-clients/${oidcClients.scim.id}`);

		await page.getByRole('tab', { name: 'SCIM Provisioning' }).click();

		await page.getByLabel('SCIM Endpoint').fill('http://scim.provider/api');
		await page.getByLabel('SCIM Token').fill('supersecrettoken');

		await page.getByRole('button', { name: 'Enable' }).click();

		await expect(page.locator('[data-type="success"]')).toHaveText('SCIM enabled successfully.');

		await page.reload();

		await expect(page.getByLabel('SCIM Endpoint')).toHaveValue('http://scim.provider/api');
		await expect(page.getByLabel('SCIM Token')).toHaveValue('supersecrettoken');
	});

	test('Update SCIM of OIDC client', async ({ page }) => {
		await configureOidcClient(page);

		await page.goto(`/settings/admin/oidc-clients/${oidcClients.scim.id}`);
		await page.getByRole('tab', { name: 'SCIM Provisioning' }).click();

		await page.getByLabel('SCIM Endpoint').fill('http://new.scim.provider/api');
		await page.getByLabel('SCIM Token').fill('evenmoresecrettoken');

		await page.getByRole('button', { name: 'Save' }).click();

		await expect(page.locator('[data-type="success"]')).toHaveText(
			'SCIM configuration updated successfully.'
		);

		await page.reload();

		await expect(page.getByLabel('SCIM Endpoint')).toHaveValue('http://new.scim.provider/api');
		await expect(page.getByLabel('SCIM Token')).toHaveValue('evenmoresecrettoken');
	});

	test('Disable SCIM of OIDC client', async ({ page }) => {
		await configureOidcClient(page);

		await page.goto(`/settings/admin/oidc-clients/${oidcClients.scim.id}`);
		await page.getByRole('tab', { name: 'SCIM Provisioning' }).click();

		await page.getByRole('button', { name: 'Disable' }).click();
		await page.getByRole('button', { name: 'Disable' }).nth(1).click();

		await expect(page.locator('[data-type="success"]')).toHaveText('SCIM disabled successfully.');

		await page.reload();

		await expect(page.getByRole('button', { name: 'Enable' })).toBeVisible();
		await expect(page.getByLabel('SCIM Endpoint')).toHaveValue('');
		await expect(page.getByLabel('SCIM Token')).toHaveValue('');
	});
});

test.describe('SCIM Sync', () => {
	test.skip(
		!process.env.SCIM_SERVICE_PROVIDER_URL || !process.env.SCIM_SERVICE_PROVIDER_URL_INTERNAL,
		'Skipping SCIM Sync tests because SCIM_SERVICE_PROVIDER_URL or SCIM_SERVICE_PROVIDER_URL_INTERNAL is not set'
	);

	test.beforeEach(async ({ page }) => {
		await Promise.all([configureOidcClient(page), cleanupScimServiceProvider()]);
	});

	test('Sync client', async ({ page }) => {
		await syncScimServiceProvider(page);

		const scimUsers = await getScimResources('Users');
		await expect(scimUsers.length).toBe(2);

		const groups = await getScimResources('Groups');
		await expect(groups.length).toBe(2);

		const timUser = scimUsers.find((u: any) => u.userName === 'tim');
		await expect(timUser).toBeDefined();
		await expect(timUser).toMatchObject({
			externalId: users.tim.id,
			emails: [
				{
					value: users.tim.email,
					primary: true
				}
			],
			name: {
				givenName: users.tim.firstname,
				familyName: users.tim.lastname
			},
			displayName: users.tim.displayName,
			active: true
		});
	});

	test('Remove allowed group and sync', async ({ page }) => {
		await syncScimServiceProvider(page);

		await page.getByRole('tab', { name: 'Allowed user groups' }).click();

		const developersCheckbox = page
			.getByRole('row', { name: userGroups.developers.name })
			.getByRole('checkbox');
		await developersCheckbox.click();
		await expect(developersCheckbox).toHaveAttribute('data-state', 'unchecked');

		await page.getByRole('button', { name: 'Save' }).click();
		await expect(page.getByText('Allowed user groups updated successfully', { exact: true })).toBeVisible();

		await syncScimServiceProvider(page);

		const scimUsers = await getScimResources('Users');
		await expect(scimUsers.length).toBe(1);
		await expect(scimUsers.find((u: any) => u.userName === users.tim.username)).toBeDefined();

		const scimGroups = await getScimResources('Groups');
		await expect(scimGroups.length).toBe(1);
		await expect(
			scimGroups.find((g: any) => g.displayName === userGroups.designers.friendlyName)
		).toBeDefined();
	});

	test('Remove group restrictions and sync', async ({ page }) => {
		await syncScimServiceProvider(page);

		await page.getByRole('tab', { name: 'Allowed user groups' }).click();

		await page.getByRole('button', { name: 'Unrestrict' }).click();
		await page.getByRole('button', { name: 'Unrestrict' }).nth(1).click();

		await syncScimServiceProvider(page);

		const scimUsers = await getScimResources('Users');
		await expect(scimUsers.length).toBe(3);

		const scimGroups = await getScimResources('Groups');
		await expect(scimGroups.length).toBe(2);
	});
});

async function getScimResources(resourceType: 'Users' | 'Groups') {
	const response = await fetch(`${process.env.SCIM_SERVICE_PROVIDER_URL}/${resourceType}`).then(
		(res) => res.json()
	);
	return response['Resources'];
}
