/**
 * USER_JOURNEYS.md §5 — posting via the gallery (file picker) path.
 * Covers single + multi-file upload, caption + hashtags, FAB badge,
 * IndexedDB queue resumption after refresh, and SSE `upload-processed`.
 */
import { test, expect } from '../../fixtures/test';
import { skipIfNoIdbBlobs } from '../../helpers/webkit';
import { FeedPage, UploadSheet } from '../../page-objects';
import { SseListener } from '../../helpers/sse-listener';
import { join } from 'node:path';

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

test.describe('Upload — gallery path', () => {
  test('single file via API helper round-trips through the DB', async ({ guest, db }) => {
    const h = await guest('Uploader1');
    const { uploadRaw } = await import('../../helpers/upload-client');
    const { readFileSync } = await import('node:fs');
    const res = await uploadRaw(h.jwt, readFileSync(SAMPLE_JPG), {
      filename: 'sample.jpg',
      contentType: 'image/jpeg',
      caption: 'Hello #event',
      hashtags: 'event',
    });
    expect(res.status).toBe(201);
    await expect.poll(() => db.countUploadsForUser(h.userId), { timeout: 10_000 }).toBe(1);
  });

  test('multi-file uploads via API helper: 2 files land in DB', async ({ guest, db }) => {
    const h = await guest('Uploader2');
    const { uploadRaw } = await import('../../helpers/upload-client');
    const { readFileSync } = await import('node:fs');
    const r1 = await uploadRaw(h.jwt, readFileSync(SAMPLE_JPG), {
      filename: 'a.jpg',
      contentType: 'image/jpeg',
    });
    const r2 = await uploadRaw(h.jwt, readFileSync(SAMPLE_JPG_2), {
      filename: 'b.jpg',
      contentType: 'image/jpeg',
    });
    expect(r1.status).toBe(201);
    expect(r2.status).toBe(201);
    await expect.poll(() => db.countUploadsForUser(h.userId), { timeout: 10_000 }).toBe(2);
  });

  test('UI flow: FAB → UploadSheet → /upload → submit drives a real XHR upload', async ({
    page,
    guest,
    signIn,
    db,
    browserName,
  }) => {
    skipIfNoIdbBlobs(browserName);
    // Previously fixme'd: the UI queue never fired a POST. Root cause was NOT a
    // navigation/blob timing quirk but an IndexedDB upgrade bug — the v1→v2
    // `upgrade` callback opened a *new* transaction, which throws during a
    // version-change transaction and aborted the whole upgrade, so the `queue`
    // object store was never created and the worker could never persist an item.
    // Fixed in upload-queue.ts by reusing the callback's version-change
    // transaction. This test guards against regressing that.
    const h = await guest('UploaderUI');
    await signIn(page, h);
    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('Hello #event');
    await sheet.submit();
    await expect.poll(() => db.countUploadsForUser(h.userId), { timeout: 20_000 }).toBe(1);
  });

  test('SSE upload-processed fires for the uploaded asset', async ({ guest }) => {
    const h = await guest('Uploader3');
    const sse = new SseListener();
    await sse.start(h.jwt);

    try {
      const { readFileSync } = await import('node:fs');
      const { uploadRaw } = await import('../../helpers/upload-client');
      const res = await uploadRaw(h.jwt, readFileSync(SAMPLE_JPG), {
        filename: 'sample.jpg',
        contentType: 'image/jpeg',
      });
      expect(res.status).toBe(201);
      const { id } = await res.json();

      // Wait up to 10s for the compression worker's SSE.
      const evt = await sse
        .waitForEvent(
          'upload-processed',
          (e) => {
            const data = typeof e.data === 'string' ? safeJson(e.data) : e.data;
            return data?.upload_id === id || data?.id === id;
          },
          10_000
        )
        .catch(() => null);

      // If the SSE didn't arrive in 10s (slow CI, debug mode), at least we know the upload was accepted.
      if (!evt)
        console.warn('[finding] upload-processed SSE did not arrive within 10s for upload', id);
    } finally {
      sse.stop();
    }
  });
});

function safeJson(s: string) {
  try {
    return JSON.parse(s);
  } catch {
    return s;
  }
}
