/**
 * R-E2E series — Fase 2b.1 (dual-browser-context Realtime sync)
 *
 * Each test spins up two browser contexts (Ana + Borja), each with its own
 * Keycloak session, and verifies that a mutation in one context is visible
 * in the other without a page reload.
 */
import { test, expect, type Browser } from '@playwright/test';
import { USERS } from '../fixtures/users.js';
import { loginAs } from '../fixtures/login.js';

const SEED_LIST_PATH = '/lists/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb';
const ADD_ITEM_PLACEHOLDER = /add item|añadir producto/i;

async function loggedInListPage(browser: Browser, user: (typeof USERS)[keyof typeof USERS]) {
	const context = await browser.newContext();
	const page = await context.newPage();
	await loginAs(page, user);
	await page.goto(SEED_LIST_PATH);
	await expect(page.getByPlaceholder(ADD_ITEM_PLACEHOLDER)).toBeVisible({ timeout: 15_000 });
	return { context, page };
}

test.describe('Realtime sync — two sessions on the same list', () => {
	test('R-E-01: Ana adds an item → Borja sees it without refreshing', async ({ browser }) => {
		const ana = await loggedInListPage(browser, USERS.ana);
		const borja = await loggedInListPage(browser, USERS.borja);

		try {
			const itemName = `R-E-01-${Date.now()}`;

			// Ana adds the item via her sticky form
			const anaInput = ana.page.getByPlaceholder(ADD_ITEM_PLACEHOLDER);
			await anaInput.fill(itemName);
			await anaInput.press('Enter');
			await expect(ana.page.getByText(itemName)).toBeVisible({ timeout: 5_000 });

			// Borja should see it land via Realtime, no reload
			await expect(borja.page.getByText(itemName)).toBeVisible({ timeout: 5_000 });
		} finally {
			await ana.context.close();
			await borja.context.close();
		}
	});

	test('R-E-02: Ana renames an item → Borja sees the new name via Realtime UPDATE', async ({ browser }) => {
		// Fase 5.10 removed the checkbox/toggle button from the list detail
		// view. Check/uncheck is a swipe gesture (unreliable under Chromium
		// touch emulation). Renaming an item via the double-tap overlay fires
		// the same realtime UPDATE path — this test still covers Ana → Borja
		// sync; Vitest integration R-02 covers the UPDATE-row-payload invariant.
		const ana = await loggedInListPage(browser, USERS.ana);
		const borja = await loggedInListPage(browser, USERS.borja);

		borja.page.on('console', (m) => {
			if (m.type() === 'error') console.log(`    borja [err] ${m.text()}`);
		});

		try {
			const originalName = `R-E-02-orig-${Date.now()}`;
			const renamedName = `R-E-02-new-${Date.now()}`;

			const anaInput = ana.page.getByPlaceholder(ADD_ITEM_PLACEHOLDER);
			await anaInput.fill(originalName);
			await anaInput.press('Enter');
			await expect(ana.page.getByText(originalName)).toBeVisible({ timeout: 5_000 });
			await expect(borja.page.getByText(originalName)).toBeVisible({ timeout: 5_000 });

			// Wait a beat so the optimistic tempId is swapped for the real one.
			await ana.page.waitForTimeout(500);

			// Open the overlay via the row's name button (double-click = double-tap).
			const anaRowNameBtn = ana.page
				.locator('[role="listitem"]')
				.filter({ hasText: originalName })
				.getByRole('button', { name: originalName })
				.first();
			await anaRowNameBtn.dblclick();
			const overlay = ana.page.getByTestId('edit-overlay');
			await expect(overlay).toBeVisible({ timeout: 3_000 });
			const overlayInput = overlay.getByPlaceholder(/add item|añadir producto/i);
			await overlayInput.fill(renamedName);
			await overlay.getByRole('button', { name: /^confirm$|^confirmar$/i }).click();

			// Ana's UI shows the new name, and Borja's catches up via Realtime.
			await expect(ana.page.getByText(renamedName)).toBeVisible({ timeout: 5_000 });
			await expect(borja.page.getByText(renamedName)).toBeVisible({ timeout: 10_000 });
		} finally {
			await ana.context.close();
			await borja.context.close();
		}
	});
});
