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

async function setSignupMode(
	page: Page,
	mode: 'Disabled' | 'Signup with token' | 'Open Signup',
	signout = true
) {
	await page.goto('/settings/admin/application-configuration');

	await page.getByRole('button', { name: 'Expand card' }).nth(1).click();
	await page.getByRole('button', { name: 'Enable User Signups' }).click();
	await page.getByRole('option', { name: mode }).click();
	await page.getByRole('button', { name: 'Save' }).nth(1).click();

	await expect(page.locator('[data-type="success"]').last()).toHaveText(
		'User creation settings updated successfully.'
	);

	if (signout) {
		await page.context().clearCookies();
		await page.goto('/login');
	}
}

test.describe('Signup Token Creation', () => {
	test.beforeEach(async ({ page }) => {
		await cleanupBackend();
		await setSignupMode(page, 'Signup with token', false);
	});

	test('Create signup token', async ({ page }) => {
		await page.goto('/settings/admin/users');

		await page.getByLabel('Create options').getByRole('button').click();
		await page.getByRole('menuitem', { name: 'Create Signup Token' }).click();
		await page.getByLabel('Expiration').click();
		await page.getByRole('option', { name: 'week' }).click();

		await page.getByLabel('Usage Limit').fill('8');

		await page.getByLabel('User Groups').click();
		await page.getByRole('option', { name: userGroups.developers.name }).click();
		await page.getByRole('option', { name: userGroups.designers.name }).click();
		await page.getByLabel('User Groups').click();

		await page.getByRole('button', { name: 'Create', exact: true }).click();
		await page.getByRole('button', { name: 'Close' }).click();

		await page.getByLabel('Create options').getByRole('button').click();
		await page.getByRole('menuitem', { name: 'View Active Signup Tokens' }).click();
		await page.getByLabel('Manage Signup Tokens').getByRole('button', { name: 'View' }).click();

		await page.getByRole('menuitemcheckbox', { name: 'User Groups' }).click();

		const row = page.getByRole('row').last();
		await expect(row.getByRole('cell', { name: '0 of 8' })).toBeVisible();
		const dateInAWeek = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toLocaleDateString('en-US');
		await expect(row.getByRole('cell', { name: dateInAWeek })).toBeVisible();
		await expect(row.getByRole('cell', { name: userGroups.developers.name })).toBeVisible();
		await expect(row.getByRole('cell', { name: userGroups.designers.name })).toBeVisible();
	});
});

test.describe('Initial User Signup', () => {
	test.beforeEach(async ({ page }) => {
		await page.context().clearCookies();
	});

	test('Initial Signup - success flow', async ({ page }) => {
		await cleanupBackend({ skipSeed: true });
		await page.goto('/setup');
		await page.getByLabel('First name').fill('Jane');
		await page.getByLabel('Last name').fill('Smith');
		await page.getByLabel('Username').fill('janesmith');
		await page.getByLabel('Email').fill('jane.smith@test.com');
		await page.getByRole('button', { name: 'Sign Up' }).click();
		await page.waitForURL('/signup/add-passkey');
		await expect(page.getByText('Set up your passkey')).toBeVisible();
	});

	test('Initial Signup - setup already completed', async ({ page }) => {
		await cleanupBackend();
		await page.goto('/setup');
		await page.getByLabel('First name').fill('Test');
		await page.getByLabel('Last name').fill('User');
		await page.getByLabel('Username').fill('testuser123');
		await page.getByLabel('Email').fill(users.tim.email);
		await page.getByRole('button', { name: 'Sign Up' }).click();
		await expect(page.getByText('Setup already completed')).toBeVisible();
	});
});

test.describe('User Signup', () => {
	test.beforeEach(async () => await cleanupBackend());

	test.describe('Signup Flows', () => {
		test('Signup is disabled - shows error message', async ({ page }) => {
			await setSignupMode(page, 'Disabled');

			await page.goto('/signup');

			await expect(page.getByText('User signups are currently disabled')).toBeVisible();
		});

		test('Signup with token - success flow', async ({ page }) => {
			await setSignupMode(page, 'Signup with token');

			await page.goto(`/st/${signupTokens.valid.token}`);

			await page.getByLabel('First name').fill('John');
			await page.getByLabel('Last name').fill('Doe');
			await page.getByLabel('Username').fill('johndoe');
			await page.getByLabel('Email').fill('john.doe@test.com');

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

			await page.waitForURL('/signup/add-passkey');
			await expect(page.getByText('Set up your passkey')).toBeVisible();

			const response = await page.request.get('/api/users/me').then((res) => res.json());
			expect(response.userGroups.map((g) => g.id)).toContain(userGroups.developers.id);
		});

		test('Signup with token - invalid token shows error', async ({ page }) => {
			await setSignupMode(page, 'Signup with token');

			await page.goto('/st/invalid-token-123');
			await page.getByLabel('First name').fill('Complete');
			await page.getByLabel('Last name').fill('User');
			await page.getByLabel('Username').fill('completeuser');
			await page.getByLabel('Email').fill('complete.user@test.com');
			await page.getByRole('button', { name: 'Sign Up' }).click();

			await expect(page.getByText('Token is invalid or expired.')).toBeVisible();
		});

		test('Signup with token - no token in URL shows error', async ({ page }) => {
			await setSignupMode(page, 'Signup with token');

			await page.goto('/signup');

			await expect(
				page.getByText('A valid signup token is required to create an account.')
			).toBeVisible();
		});

		test('Open signup - success flow', async ({ page }) => {
			await setSignupMode(page, 'Open Signup');

			await page.goto('/signup');

			await expect(page.getByText('Create your account to get started')).toBeVisible();

			await page.getByLabel('First name').fill('Jane');
			await page.getByLabel('Last name').fill('Smith');
			await page.getByLabel('Username').fill('janesmith');
			await page.getByLabel('Email').fill('jane.smith@test.com');

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

			await page.waitForURL('/signup/add-passkey');
			await expect(page.getByText('Set up your passkey')).toBeVisible();
		});

		test('Open signup - validation errors', async ({ page }) => {
			await setSignupMode(page, 'Open Signup');

			await page.goto('/signup');

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

			await expect(page.getByText('Invalid email address').first()).toBeVisible();
		});

		test('Open signup - duplicate email shows error', async ({ page }) => {
			await setSignupMode(page, 'Open Signup');

			await page.goto('/signup');

			await page.getByLabel('First name').fill('Test');
			await page.getByLabel('Last name').fill('User');
			await page.getByLabel('Username').fill('testuser123');
			await page.getByLabel('Email').fill(users.tim.email);

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

			await expect(page.getByText('Email is already in use.')).toBeVisible();
		});

		test('Open signup - duplicate username shows error', async ({ page }) => {
			await setSignupMode(page, 'Open Signup');

			await page.goto('/signup');

			await page.getByLabel('First name').fill('Test');
			await page.getByLabel('Last name').fill('User');
			await page.getByLabel('Username').fill(users.tim.username);
			await page.getByLabel('Email').fill('newuser@test.com');

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

			await expect(page.getByText('Username is already in use.')).toBeVisible();
		});

		test('Complete signup flow with passkey creation', async ({ page }) => {
			await setSignupMode(page, 'Open Signup');

			await page.goto('/signup');
			await page.getByLabel('First name').fill('Complete');
			await page.getByLabel('Last name').fill('User');
			await page.getByLabel('Username').fill('completeuser');
			await page.getByLabel('Email').fill('complete.user@test.com');
			await page.getByRole('button', { name: 'Sign Up' }).click();

			await page.waitForURL('/signup/add-passkey');

			await (await passkeyUtil.init(page)).addPasskey('timNew');
			await page.getByRole('button', { name: 'Add Passkey' }).click();

			await page.waitForURL('/settings/account');
			await expect(page.getByText('Single Passkey Configured')).toBeVisible();
		});

		test('Skip passkey creation during signup', async ({ page }) => {
			await setSignupMode(page, 'Open Signup');

			await page.goto('/signup');
			await page.getByLabel('First name').fill('Skip');
			await page.getByLabel('Last name').fill('User');
			await page.getByLabel('Username').fill('skipuser');
			await page.getByLabel('Email').fill('skip.user@test.com');
			await page.getByRole('button', { name: 'Sign Up' }).click();

			await page.waitForURL('/signup/add-passkey');

			await page.getByRole('button', { name: 'Skip for now' }).click();

			await expect(page.getByText('Skip Passkey Setup')).toBeVisible();
			await page.getByRole('button', { name: 'Skip for now' }).nth(1).click();

			await page.waitForURL('/settings/account');
			await expect(page.getByText('Passkey missing')).toBeVisible();
		});

		test('Token usage limit is enforced', async ({ page }) => {
			await setSignupMode(page, 'Signup with token');

			await page.goto(`/st/${signupTokens.fullyUsed.token}`);
			await page.getByLabel('First name').fill('Complete');
			await page.getByLabel('Last name').fill('User');
			await page.getByLabel('Username').fill('completeuser');
			await page.getByLabel('Email').fill('complete.user@test.com');
			await page.getByRole('button', { name: 'Sign Up' }).click();

			await expect(page.getByText('Token is invalid or expired.')).toBeVisible();
		});
	});
});
