/**
 * Re-review regression guard — Chain B1 ("offline queue must auto-resume").
 *
 * Bug that was fixed: a file staged while OFFLINE was attempted immediately;
 * the XHR network error marked the queue item `error`, and every resume path
 * (the `online` listener, `processQueue`, `loadQueue`) only picks up `pending`
 * items — so the item was stranded until a manual "Erneut" tap.
 *
 * The fix: network failures are a distinct `NetworkError` that keeps the item
 * `pending`; `processQueue` bails while `navigator.onLine === false` (so an
 * offline-staged item is never burned to `error`); and `requeueRetriable()`
 * flips transient `error`→`pending` on the `online` event and on mount.
 *
 * This test drives a REAL browser going offline → stage+submit → reconnect and
 * asserts the upload lands with NO manual interaction. It fails on the old code
 * (item errors, never resumes) and passes on the fix.
 */
import { test, expect } from '../../fixtures/test';
import { FeedPage, UploadSheet } from '../../page-objects';
import { join } from 'node:path';

const SAMPLE_JPG = join(process.cwd(), 'fixtures', 'media', 'sample.jpg');

// White-box: read the upload queue straight out of IndexedDB so we can assert
// the item's status without depending on the (currently unrendered) queue widget.
async function queueStatuses(page: import('@playwright/test').Page): Promise<string[]> {
  return page.evaluate(async () => {
    const statuses = await new Promise<string[]>((resolve, reject) => {
      const req = indexedDB.open('eventsnap-uploads', 3);
      req.onerror = () => reject(req.error);
      req.onsuccess = () => {
        const dbh = req.result;
        const tx = dbh.transaction('queue', 'readonly');
        const all = tx.objectStore('queue').getAll();
        all.onsuccess = () => resolve(all.result.map((r: any) => r.status));
        all.onerror = () => reject(all.error);
      };
    });
    return statuses;
  });
}

test.describe('Flow re-review — offline upload auto-resume (B1)', () => {
  test('offline-staged upload stays pending, then flushes on reconnect with no manual tap', async ({
    page,
    guest,
    signIn,
    db,
  }) => {
    const g = await guest('OfflineResume');
    await signIn(page, g);
    await page.goto('/feed');
    expect(await db.countUploadsForUser(g.userId)).toBe(0);

    // Warm the code-split `/upload` route chunk while still ONLINE. Without this, the
    // client-side navigation the UploadSheet triggers would try to fetch the chunk with
    // no connectivity and hit SvelteKit's error boundary — a test artifact unrelated to
    // the upload-queue fix under test. (A production PWA service worker would cache it.)
    await page.goto('/upload');
    await page.goto('/feed');

    // Go offline BEFORE staging so the first attempt happens with no connectivity.
    await page.context().setOffline(true);

    const feed = new FeedPage(page);
    const sheet = new UploadSheet(page);
    await feed.openUploadSheet();
    await sheet.stageFiles([SAMPLE_JPG]);
    await sheet.captionInput.waitFor({ state: 'visible', timeout: 10_000 });
    await sheet.fillCaption('shot with no signal');
    await sheet.submit();
    // handleSubmit navigates to /feed after enqueuing even while offline.
    await page.waitForURL('**/feed', { timeout: 15_000 });

    // While offline: nothing may have reached the server, and — the crux of the
    // fix — the item must be parked as `pending`, NOT burned to `error`/`blocked`
    // (which on the old code would require a manual retry tap).
    await expect.poll(() => queueStatuses(page), { timeout: 8_000 }).toEqual(['pending']);
    expect(await db.countUploadsForUser(g.userId)).toBe(0);

    // Reconnect. The `online` listener must resume the queue automatically — we do
    // NOT navigate, tap retry, or otherwise touch the page.
    await page.context().setOffline(false);

    // The queued upload is now created server-side without any manual interaction.
    await expect.poll(() => db.countUploadsForUser(g.userId), { timeout: 20_000 }).toBe(1);

    // And the queue item ends terminal-good (done) or is drained — never stuck in error.
    await expect
      .poll(
        async () => {
          const s = await queueStatuses(page);
          return s.every((x) => x === 'done') || s.length === 0;
        },
        { timeout: 10_000 }
      )
      .toBe(true);
  });
});
