/**
 * USER_JOURNEYS.md §3 (recovery on a new device). Uses the standalone
 * /recover route as well as the inline-recovery flow on /join.
 */
import { test, expect } from '../../fixtures/test';
import { RecoverPage } from '../../page-objects';
import { clearAllStorage } from '../../helpers/storage-helpers';

test.describe('Auth — /recover route', () => {
  test('happy path: correct name + PIN → /feed', async ({ page, guest }) => {
    const handle = await guest('Greta');
    await clearAllStorage(page);

    const recover = new RecoverPage(page);
    await recover.goto();
    await recover.recover('Greta', handle.pin);
    await page.waitForURL('**/feed');
  });

  test('wrong PIN shows the localized error', async ({ page, guest }) => {
    const handle = await guest('Hans');
    await clearAllStorage(page);
    const recover = new RecoverPage(page);
    await recover.goto();
    await recover.recover('Hans', handle.pin === '9999' ? '0000' : '9999');
    await expect(recover.errorMessage).toContainText(/PIN ist falsch|falsch/i);
  });

  // An unknown name must be INDISTINGUISHABLE from a wrong PIN — same status, same message.
  //
  // This test used to assert the exact opposite: that an unknown name produced a distinct
  // "nicht gefunden" error. That IS the account-enumeration oracle the F4 audit fix removed
  // (recover now answers an unknown name with the same 401 "PIN ist falsch."), so reintroducing
  // the vulnerability would have made this test pass and `recover-enumeration.spec.ts` fail — two
  // tests asserting contradictory things about the same behaviour, one of them for the attacker.
  //
  // It also passed for a reason unrelated to the name: this test takes no `guest` fixture, so the
  // per-test TRUNCATE leaves no event row at all, and recover 404s with "Event nicht gefunden." —
  // which the old regex happily matched.
  test('an unknown name is indistinguishable from a wrong PIN (no enumeration oracle)', async ({
    page,
    guest,
  }) => {
    const handle = await guest('Known');
    await clearAllStorage(page);
    const recover = new RecoverPage(page);

    await recover.goto();
    await recover.recover('Doesnt-Exist-' + Date.now(), '1234');
    const unknownNameError = (await recover.errorMessage.textContent())?.trim();

    await recover.goto();
    await recover.recover('Known', handle.pin === '9999' ? '0000' : '9999');
    const wrongPinError = (await recover.errorMessage.textContent())?.trim();

    expect(unknownNameError).toBeTruthy();
    expect(
      unknownNameError,
      'an unknown name must not be distinguishable from a wrong PIN — that is an account-enumeration oracle'
    ).toBe(wrongPinError);
    expect(unknownNameError).not.toMatch(/nicht gefunden|kein benutzer/i);
  });

  test('lockout expires and counter resets (per recover handler)', async ({ api, guest, db }) => {
    const handle = await guest('Ida');
    await db.lockUserPin(handle.userId, 15);
    // Direct API call: even the correct PIN must fail while locked.
    await api.recover('Ida', handle.pin, { expectedStatus: [429] });

    // Now move the lockout into the past.
    await db.lockUserPin(handle.userId, -1);
    // Correct PIN must succeed, AND the counter must be reset so the next wrong attempt isn't immediately re-locked.
    const { body } = await api.recover('Ida', handle.pin, { expectedStatus: [200] });
    expect(body.jwt).toBeTruthy();
  });
});
