import assert from 'node:assert/strict';
import { chromium } from 'playwright';
import { fixture, password } from './fixture.js';
import { checkpoint } from './checkpoint.js';

const f = await fixture();
let browser;
try {
    browser = await chromium.launch({ headless: false, channel: 'chrome' });
    for (const name of ['hello', 'counter']) {
        const app = await checkpoint(name);
        let context;
        try {
            context = await browser.newContext();
            context.setDefaultTimeout(8000);
            const page = await context.newPage();
            await page.goto(app.origin);
            if (name === 'hello') await page.getByRole('heading', { name: 'Hello world!' }).waitFor();
            else {
                const second = await context.newPage();
                await second.goto(app.origin);
                for (const tab of [page, second]) await tab.waitForFunction(() => document.documentElement.getAttribute('data-rw-connection') === 'open');
                await page.getByRole('button', { name: 'Count 0' }).click();
                await second.getByRole('button', { name: 'Count 1' }).waitFor();
                await second.getByRole('button', { name: 'Count 1' }).click();
                await page.getByRole('button', { name: 'Count 2' }).waitFor();
            }
        } finally { try { await context?.close(); } finally { await app.close(); } }
    }
    const contexts = await Promise.all([browser.newContext(), browser.newContext()]);
    for (const context of contexts) context.setDefaultTimeout(8000);
    const [alice, bob] = await Promise.all(contexts.map(context => context.newPage()));
    const failures = [];
    for (const page of [alice, bob]) page.on('pageerror', error => failures.push(error.message));
    async function signIn(page, account) {
        await page.goto(`${f.origin}/login`);
        await page.getByLabel('Account', { exact: true }).fill(account);
        await page.getByLabel('Password', { exact: true }).fill(password);
        await page.getByRole('button', { name: 'Sign in', exact: true }).click();
        await page.waitForURL(f.origin + '/');
        await page.getByText('Connected', { exact: true }).waitFor();
    }
    await alice.goto(`${f.origin}/login`);
    await alice.getByLabel('Account', { exact: true }).fill('alice');
    await alice.getByLabel('Password', { exact: true }).fill('incorrect-password');
    await alice.getByRole('button', { name: 'Sign in', exact: true }).click();
    await alice.getByText('Unable to sign in.', { exact: false }).waitFor();
    await signIn(alice, 'alice'); await signIn(bob, 'bob');
    for (const page of [alice, bob]) {
        await page.getByLabel('Room', { exact: true }).fill('browser-game');
        await page.getByRole('button', { name: 'Join room' }).click();
    }
    await alice.waitForFunction(() => document.querySelector('#status').textContent.includes('alice, bob'));
    async function move(page, other, square, mark) {
        await page.getByRole('button', { name: `Square ${square}`, exact: true }).click();
        await other.waitForFunction(({ square, mark }) => document.querySelector(`[data-cell="${square - 1}"]`).textContent === mark, { square, mark });
    }
    await move(alice, bob, 1, 'X'); await move(bob, alice, 4, 'O');
    const reconnected = bob.waitForEvent('websocket');
    const route = f.app.sockets.routes.find(route => route.path === '/match');
    for (const socket of route.clients.values()) if (socket.context.principal === 'bob') socket.terminate();
    await reconnected;
    await bob.getByText('Connected', { exact: true }).waitFor();
    await bob.waitForFunction(() => document.querySelector('#status').textContent.includes('Room browser-game'));
    await move(alice, bob, 2, 'X'); await move(bob, alice, 5, 'O'); await move(alice, bob, 3, 'X');
    for (const page of [alice, bob]) {
        await page.waitForFunction(() => document.querySelector('#status').textContent.includes('X wins!'));
        assert.equal(await page.locator('#board button:enabled').count(), 0);
    }
    await bob.close();
    await alice.waitForFunction(() => document.querySelector('#status').textContent.endsWith('Online: alice'));
    await alice.getByRole('button', { name: 'Sign out all sessions' }).click();
    await alice.waitForURL(`${f.origin}/login`);
    assert.deepEqual(failures, []);
    console.log('PASS: headed Chrome, actual forms, two accounts, shared board, reconnect, disconnect presence, win and logout.');
} finally { try { await browser?.close(); } finally { await f.close(); } }
