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

test.beforeEach(async () => await cleanupBackend());

test.describe('Create OIDC client', () => {
	async function createClientTest(page: Page, clientId?: string) {
		const oidcClient = oidcClients.pingvinShare;
		await page.goto('/settings/admin/oidc-clients');
		await page.getByRole('button', { name: 'Add OIDC Client' }).click();

		await page.getByLabel('Name').fill(oidcClient.name);
		await page.getByLabel('Client Launch URL').fill(oidcClient.launchURL);

		await page.getByRole('button', { name: 'Add' }).first().click();
		await page.getByTestId('callback-url-1').fill(oidcClient.callbackUrl);

		await page.getByRole('button', { name: 'Add another' }).click();
		await page.getByTestId('callback-url-2').fill(oidcClient.secondCallbackUrl);

		await page.locator('[role="tab"][data-value="light-logo"]').first().click();
		await page.setInputFiles('#oidc-client-logo-light', 'resources/images/pingvin-share-logo.png');
		await page.locator('[role="tab"][data-value="dark-logo"]').first().click();
		await page.setInputFiles('#oidc-client-logo-dark', 'resources/images/pingvin-share-logo.png');

		if (clientId) {
			await page.getByRole('button', { name: 'Show Advanced Options' }).click();
			await page.getByLabel('Client ID').fill(clientId);
		}

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

		await expect(page.locator('[data-type="success"]')).toHaveText(
			'OIDC client created successfully'
		);

		const resolvedClientId = (await page.getByTestId('client-id').innerText()).trim();
		const clientSecret = (await page.getByTestId('client-secret').innerText()).trim();

		if (clientId) {
			expect(resolvedClientId).toBe(clientId);
		} else {
			expect(resolvedClientId).toMatch(/^[\w-]{36}$/);
		}

		expect(clientSecret).toMatch(/^\w{32}$/);

		await expect(page.getByLabel('Name')).toHaveValue(oidcClient.name);
		await expect(page.getByTestId('callback-url-1')).toHaveValue(oidcClient.callbackUrl);
		await expect(page.getByTestId('callback-url-2')).toHaveValue(oidcClient.secondCallbackUrl);
		await expect(page.getByRole('img', { name: `${oidcClient.name} logo` }).first()).toBeVisible();

		const res = await page.request.get(`/api/oidc/clients/${resolvedClientId}/logo`);
		expect(res.ok()).toBeTruthy();
	}

	test('with auto-generated client ID', async ({ page }) => {
		await createClientTest(page);
	});

	test('with custom client ID', async ({ page }) => {
		await createClientTest(page, '123e4567-e89b-12d3-a456-426614174000');
	});
});

test('Edit OIDC client', async ({ page }) => {
	const oidcClient = oidcClients.nextcloud;
	await page.goto(`/settings/admin/oidc-clients/${oidcClient.id}`);

	await page.getByLabel('Name').fill('Nextcloud updated');
	await page.getByTestId('callback-url-1').first().fill('http://nextcloud-updated/auth/callback');
	await page.locator('[role="tab"][data-value="light-logo"]').first().click();
	await page.setInputFiles('#oidc-client-logo-light', 'resources/images/cloud-logo.png');
	await page.locator('[role="tab"][data-value="dark-logo"]').first().click();
	await page.setInputFiles('#oidc-client-logo-dark', 'resources/images/cloud-logo.png');
	await page.getByLabel('Client Launch URL').fill(oidcClient.launchURL);
	await page.getByRole('button', { name: 'Save' }).click();

	await expect(page.locator('[data-type="success"]')).toHaveText(
		'OIDC client updated successfully'
	);
	await expect(page.getByRole('img', { name: 'Nextcloud updated logo' }).first()).toBeVisible();
	await page.request
		.get(`/api/oidc/clients/${oidcClient.id}/logo`)
		.then((res) => expect.soft(res.status()).toBe(200));
});

test('Create new OIDC client secret', async ({ page }) => {
	const oidcClient = oidcClients.nextcloud;
	await page.goto(`/settings/admin/oidc-clients/${oidcClient.id}`);

	await page.getByLabel('Create new client secret').click();
	await page.getByRole('button', { name: 'Generate' }).click();

	await expect(page.locator('[data-type="success"]')).toHaveText(
		'New client secret created successfully'
	);
	expect((await page.getByTestId('client-secret').textContent())?.length).toBe(32);
});

test('Delete OIDC client', async ({ page }) => {
	const oidcClient = oidcClients.nextcloud;
	await page.goto('/settings/admin/oidc-clients');

	await page
		.getByRole('row', { name: oidcClient.name })
		.getByRole('button', { name: 'Toggle menu' })
		.click();

	await page.getByRole('menuitem', { name: 'Delete' }).click();

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

	await expect(page.locator('[data-type="success"]')).toHaveText(
		'OIDC client deleted successfully'
	);
	await expect(page.getByRole('row', { name: oidcClient.name })).not.toBeVisible();
});

test('Filter OIDC clients by PAR requirement', async ({ page, request }) => {
	const parClient = oidcClients.parClient;

	// Enable PAR on the PAR test client
	await request.put(`/api/oidc/clients/${parClient.id}`, {
		data: {
			name: parClient.name,
			callbackURLs: [parClient.callbackUrl],
			logoutCallbackURLs: [],
			isPublic: false,
			pkceEnabled: false,
			requiresReauthentication: false,
			requiresPushedAuthorizationRequests: true,
			credentials: { federatedIdentities: [] },
			isGroupRestricted: false
		}
	});

	await page.goto('/settings/admin/oidc-clients');

	// Open PAR filter and select "Yes"
	await page.getByTestId('facet-par-trigger').click();
	await page.getByTestId('facet-par-option-true').click();

	// Only the PAR client should be visible
	await expect(page.getByRole('row', { name: parClient.name })).toBeVisible();
	await expect(page.getByRole('row', { name: oidcClients.nextcloud.name })).not.toBeVisible();

	// Deselect "Yes" and select "No" to invert the filter
	await page.getByTestId('facet-par-option-true').click();
	await page.getByTestId('facet-par-option-false').click();

	// PAR client should be hidden, others visible
	await expect(page.getByRole('row', { name: oidcClients.nextcloud.name })).toBeVisible();
	await expect(page.getByRole('row', { name: parClient.name })).not.toBeVisible();
});

test('Update OIDC client allowed user groups', async ({ page }) => {
	await page.goto(`/settings/admin/oidc-clients/${oidcClients.nextcloud.id}`);

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

	await page.getByRole('row', { name: userGroups.designers.name }).getByRole('checkbox').click();
	await page.getByRole('row', { name: userGroups.developers.name }).getByRole('checkbox').click();

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

	await expect(page.getByText('Allowed user groups updated successfully')).toBeVisible();

	await page.reload();

	await expect(
		page.getByRole('row', { name: userGroups.designers.name }).getByRole('checkbox')
	).toHaveAttribute('data-state', 'checked');
	await expect(
		page.getByRole('row', { name: userGroups.developers.name }).getByRole('checkbox')
	).toHaveAttribute('data-state', 'checked');
});
