/**
 * Regression guard — the role must follow the identity, not the tab.
 *
 * The `role` store is a module-level singleton seeded ONCE at import. `goto()` is a
 * client-side navigation, so leaving and re-joining in the same tab re-imports nothing and
 * re-runs no `onMount` — the previous user's role simply stayed. A host who left and a
 * guest who then joined kept `isStaff === true` and were offered "🚫 Beitrag entfernen" on
 * other people's photos. The backend 403s the delete, so it was a false affordance rather
 * than a privilege escalation, but `/feed` never fetched `/me/context`, so it never
 * self-corrected either — it survived until a hard reload.
 *
 * The mirror case matters just as much and is easier to forget: a guest who recovers into a
 * host account must GAIN the affordance without a reload.
 */
import { test, expect } from '../../fixtures/test';
import { seedUpload } from '../../helpers/seed';
import { JoinPage } from '../../page-objects';

const REMOVE = /beitrag entfernen/i;

test.describe('Role — follows the identity across a same-tab switch', () => {
  test('a guest joining after a host leaves does NOT inherit host actions', async ({
    page,
    host,
    guest,
    signIn,
  }) => {
    // Someone else's photo — the only kind the removal action is offered on.
    const author = await guest('RoleAuthor');
    await seedUpload(author.jwt);

    // 1. Host is signed in and DOES see the moderation action. Establishing this first is
    //    what makes the negative assertion below meaningful.
    await signIn(page, host);
    await page.goto('/feed');
    const card = page.locator('article').filter({ hasText: author.displayName }).first();
    await expect(card).toBeVisible({ timeout: 15_000 });
    await card.getByRole('button', { name: 'Mehr Aktionen' }).click();
    await expect(page.getByRole('button', { name: REMOVE })).toBeVisible();
    await page.keyboard.press('Escape');

    // 2. Host leaves, in-app — no reload. This is the path the "Abmelden" button takes.
    await page.goto('/account');
    await page.getByTestId('account-logout').click();
    const confirm = page.getByTestId('confirm-sheet-confirm');
    if (await confirm.isVisible().catch(() => false)) await confirm.click();
    await page.waitForURL('**/join', { timeout: 10_000 });

    // 3. A brand-new guest joins in the same tab — the real flow, PIN modal and all.
    const join = new JoinPage(page);
    await join.joinAs(`Nachzuegler${Date.now() % 100000}`);
    await join.continueToFeed();
    await expect(page).toHaveURL(/\/feed$/, { timeout: 15_000 });

    // 4. They must NOT be offered moderation on someone else's photo.
    const card2 = page.locator('article').filter({ hasText: author.displayName }).first();
    await expect(card2).toBeVisible({ timeout: 15_000 });
    await card2.getByRole('button', { name: 'Mehr Aktionen' }).click();
    await expect(
      page.getByRole('button', { name: REMOVE }),
      'a fresh guest must not inherit the previous user’s role'
    ).toHaveCount(0);
  });

  test('a guest who recovers into a host account GAINS host actions without a reload', async ({
    page,
    api,
    adminToken,
    guest,
    signIn,
  }) => {
    // The mirror. If the fix only cleared the role it would pass the test above and still
    // leave a real host with no moderation until they reloaded.
    const author = await guest('RoleAuthor2');
    await seedUpload(author.jwt);

    const futureHost = await guest('WillBeHost');
    await signIn(page, futureHost);
    await page.goto('/feed');
    const card = page.locator('article').filter({ hasText: author.displayName }).first();
    await expect(card).toBeVisible({ timeout: 15_000 });
    await card.getByRole('button', { name: 'Mehr Aktionen' }).click();
    await expect(page.getByRole('button', { name: REMOVE })).toHaveCount(0);
    await page.keyboard.press('Escape');

    // Promote them server-side. Their resident JWT still claims `role: guest`.
    await api.setRole(adminToken, futureHost.userId, 'host');
    const claim = JSON.parse(Buffer.from(futureHost.jwt.split('.')[1], 'base64').toString());
    expect(claim.role, 'the token must still be stale for this to prove anything').toBe('guest');

    // A plain in-app navigation back to the feed must pick up the live role.
    await page.goto('/account');
    await page.goto('/feed');
    const card2 = page.locator('article').filter({ hasText: author.displayName }).first();
    await expect(card2).toBeVisible({ timeout: 15_000 });
    await card2.getByRole('button', { name: 'Mehr Aktionen' }).click();
    await expect(
      page.getByRole('button', { name: REMOVE }),
      'the live role from /me/context must reach the feed'
    ).toBeVisible({ timeout: 10_000 });
  });
});
