/**
 * E2E Tests for Push Notifications
 *
 * Tests the complete push notification workflow using Playwright:
 * - Permission granting
 * - Subscription creation
 * - Server registration
 * - Manual test notifications
 * - Unsubscribe flow
 * - localStorage persistence
 *
 * Note: These tests require the dev server to be running.
 */

import { test, expect, type BrowserContext } from '@playwright/test';

test.describe('Push Notifications E2E', () => {
	let context: BrowserContext;

	test.beforeEach(async ({ browser }) => {
		// Create new context with notification permissions granted
		context = await browser.newContext();
		await context.grantPermissions(['notifications']);
	});

	test.afterEach(async () => {
		await context?.close();
	});

	test('should subscribe to push notifications', async () => {
		const page = await context.newPage();
		await page.goto('/');
		await page.waitForLoadState('networkidle');

		// Wait for service worker to be registered
		await page.waitForFunction(() => 'serviceWorker' in navigator && 'PushManager' in window);

		// Find the notification toggle button
		const toggleButton = page.getByRole('button', { name: /enable notifications/i });
		await expect(toggleButton).toBeVisible();

		// Click to enable notifications
		await toggleButton.click();

		// Wait for subscription to complete
		await page.waitForTimeout(2000);

		// Verify subscription was created in browser
		const subscription = await page.evaluate(async () => {
			const registration = await navigator.serviceWorker.ready;
			const sub = await registration.pushManager.getSubscription();
			return sub
				? {
						endpoint: sub.endpoint,
						hasKeys: !!(sub as any).keys
					}
				: null;
		});

		expect(subscription).not.toBeNull();
		expect(subscription?.endpoint).toBeTruthy();
		expect(subscription?.endpoint).toContain('https://');
		expect(subscription?.hasKeys).toBe(true);

		// Verify button text changed to "Disable Notifications"
		await expect(toggleButton).toHaveText(/disable notifications/i);

		await page.close();
	});

	test('should show test notification buttons when subscribed', async () => {
		const page = await context.newPage();
		await page.goto('/');
		await page.waitForLoadState('networkidle');

		// Wait for service worker
		await page.waitForFunction(() => 'serviceWorker' in navigator);

		// Enable notifications first
		const toggleButton = page.getByRole('button', { name: /enable notifications/i });
		await toggleButton.click();
		await page.waitForTimeout(2000);

		// Verify test buttons are visible
		const testSuccessButton = page.getByRole('button', { name: /test success/i });
		const testErrorButton = page.getByRole('button', { name: /test error/i });
		const testProgressButton = page.getByRole('button', { name: /test progress/i });

		await expect(testSuccessButton).toBeVisible();
		await expect(testErrorButton).toBeVisible();
		await expect(testProgressButton).toBeVisible();

		await page.close();
	});

	test('should send test notifications', async () => {
		const page = await context.newPage();
		await page.goto('/');
		await page.waitForLoadState('networkidle');

		// Wait for service worker
		await page.waitForFunction(() => 'serviceWorker' in navigator);

		// Enable notifications first
		const toggleButton = page.getByRole('button', { name: /enable notifications/i });
		await toggleButton.click();
		await page.waitForTimeout(2000);

		// Mock the test notification API response
		await page.route('/api/notifications/test', async (route) => {
			await route.fulfill({
				status: 200,
				contentType: 'application/json',
				body: JSON.stringify({ success: true, subscriberCount: 1 })
			});
		});

		// Click test success button
		const testSuccessButton = page.getByRole('button', { name: /test success/i });
		await testSuccessButton.click();

		// Wait for and verify success message
		const successMessage = page.getByText(/✓ test success notification sent/i);
		await expect(successMessage).toBeVisible({ timeout: 5000 });

		// Verify message contains subscriber count
		await expect(successMessage).toContainText('1 subscriber');

		// Wait for auto-dismiss
		await expect(successMessage).not.toBeVisible({ timeout: 4000 });

		await page.close();
	});

	test('should unsubscribe from push notifications', async () => {
		const page = await context.newPage();
		await page.goto('/');
		await page.waitForLoadState('networkidle');

		// Wait for service worker
		await page.waitForFunction(() => 'serviceWorker' in navigator);

		// First subscribe
		const toggleButton = page.getByRole('button', { name: /enable notifications/i });
		await toggleButton.click();
		await page.waitForTimeout(2000);

		// Verify subscribed
		await expect(toggleButton).toHaveText(/disable notifications/i);

		// Now unsubscribe
		await toggleButton.click();
		await page.waitForTimeout(2000);

		// Verify subscription was removed
		const subscription = await page.evaluate(async () => {
			const registration = await navigator.serviceWorker.ready;
			return await registration.pushManager.getSubscription();
		});

		expect(subscription).toBeNull();

		// Verify button text changed back
		await expect(toggleButton).toHaveText(/enable notifications/i);

		// Verify test buttons are no longer visible
		const testSuccessButton = page.getByRole('button', { name: /test success/i });
		await expect(testSuccessButton).not.toBeVisible();

		await page.close();
	});

	test('should persist clientId in localStorage', async () => {
		const page = await context.newPage();
		await page.goto('/');
		await page.waitForLoadState('networkidle');

		// Wait for service worker
		await page.waitForFunction(() => 'serviceWorker' in navigator);

		// Enable notifications
		const toggleButton = page.getByRole('button', { name: /enable notifications/i });
		await toggleButton.click();
		await page.waitForTimeout(2000);

		// Verify clientId is stored in localStorage
		const clientId = await page.evaluate(() => {
			return localStorage.getItem('push-client-id');
		});

		expect(clientId).toBeTruthy();
		expect(clientId).toMatch(/^client_[a-f0-9-]+$/);

		// Reload page and verify clientId persists
		await page.reload();
		await page.waitForLoadState('networkidle');

		const persistedClientId = await page.evaluate(() => {
			return localStorage.getItem('push-client-id');
		});

		expect(persistedClientId).toBe(clientId);

		await page.close();
	});
});
