/**
 * Phase 3 mobile — double-tap gesture.
 *
 * The `doubletap` action is wired in two places:
 *
 *   1. FeedListCard's image button — fires `ondoubletap` → onlike(upload.id).
 *      Two rapid taps record a like. The on-screen like count increments
 *      optimistically and is reconciled by an SSE `like-update`.
 *
 *   2. LightboxModal's media wrapper — fires the heart-burst animation
 *      and calls onlike(). The animation is gated by the `heartBurst`
 *      state which the spec asserts indirectly by observing the like count
 *      increase.
 */
import { test, expect } from '../../fixtures/test';
import { uploadRaw } from '../../helpers/upload-client';
import { doubleTap } from '../../helpers/touch';
import { readFileSync } from 'node:fs';
import { join } from 'node:path';

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

async function seedUpload(token: string, caption = 'Doubletap fixture'): Promise<{ id: string }> {
  const res = await uploadRaw(token, readFileSync(SAMPLE_JPG), {
    filename: 'dt.jpg',
    contentType: 'image/jpeg',
    caption,
  });
  if (res.status !== 201)
    throw new Error(`Upload seed failed (${res.status}): ${await res.text()}`);
  return (await res.json()) as { id: string };
}

test.describe('Mobile — double-tap gesture', () => {
  test('double-tap on a feed card image button registers a like', async ({
    api,
    page,
    guest,
    signIn,
  }) => {
    const author = await guest('DtAuthor');
    const liker = await guest('DtLiker');
    const { id: uploadId } = await seedUpload(author.jwt, 'Double-tap me');

    await signIn(page, liker);
    await page.goto('/feed');

    // Locate the image button inside the card. The aria-label is "Bild vergrößern".
    const imageButton = page
      .locator('article')
      .filter({ hasText: author.displayName })
      .first()
      .getByRole('button', { name: 'Bild vergrößern' });
    await expect(imageButton).toBeVisible({ timeout: 10_000 });

    await doubleTap(page, imageButton);

    // Wait for the optimistic increment OR the SSE-confirmed count. We assert via the
    // API to avoid coupling to specific DOM markup for the like badge.
    await expect
      .poll(
        async () => {
          const feed = await api.getFeed(liker.jwt);
          // Backend returns { uploads: [...], next_cursor }.
          const list: any[] = feed.uploads ?? feed.items ?? feed;
          const row = Array.isArray(list) ? list.find((u: any) => u.id === uploadId) : undefined;
          return row?.like_count ?? row?.likes ?? 0;
        },
        { timeout: 5_000 }
      )
      .toBeGreaterThanOrEqual(1);
  });

  test('double-tap inside the lightbox triggers the heart-burst (like recorded)', async ({
    api,
    page,
    guest,
    signIn,
  }) => {
    const author = await guest('LbAuthor');
    const liker = await guest('LbLiker');
    const { id: uploadId } = await seedUpload(author.jwt, 'Lightbox heart');

    await signIn(page, liker);
    await page.goto('/feed');

    // Open the lightbox by clicking the image button.
    const imageButton = page
      .locator('article')
      .filter({ hasText: author.displayName })
      .first()
      .getByRole('button', { name: 'Bild vergrößern' });
    await expect(imageButton).toBeVisible({ timeout: 10_000 });
    await imageButton.click();

    // LightboxModal is the only dialog labelled by #lightbox-title, so target it
    // directly. (Closed sheets no longer expose role=dialog — that semantics is
    // gated on `open` — so a plain [role=dialog] match would be ambiguous only
    // while a sheet is open; the labelledby scope keeps this unambiguous.)
    const lightbox = page.locator('[role="dialog"][aria-labelledby="lightbox-title"]');
    await expect(lightbox).toBeVisible();

    // Find the inner image element to tap.
    const media = lightbox.locator('img, video').first();
    await expect(media).toBeVisible();

    await doubleTap(page, media);

    await expect
      .poll(
        async () => {
          const feed = await api.getFeed(liker.jwt);
          // Backend returns { uploads: [...], next_cursor }.
          const list: any[] = feed.uploads ?? feed.items ?? feed;
          const row = Array.isArray(list) ? list.find((u: any) => u.id === uploadId) : undefined;
          return row?.like_count ?? row?.likes ?? 0;
        },
        { timeout: 5_000 }
      )
      .toBeGreaterThanOrEqual(1);
  });
});
