/**
 * Regression guard — when the keepsake fails to build, the HOST must be told why.
 *
 * `/export/status` reported `{status, progress_pct}` and nothing else, so the host dashboard could
 * only ever render "Keepsake-Erstellung fehlgeschlagen." next to an "Erneut versuchen" button. The
 * reason WAS being written — `mark_failed` stores it on the job row — but it surfaced solely in the
 * admin dashboard's job list. The host is the person who releases the gallery, owns the retry
 * button, and is standing at the venue; the admin may be someone else entirely, or the same person
 * without the password to hand.
 *
 * That matters most for the failure this shipped alongside: the export disk preflight. Its message
 * names the two numbers that decide what to do ("benötigt ca. X GB, frei sind Y GB"), and without
 * it "Erneut versuchen" fails identically, forever, with no hint that the answer is free some space.
 *
 * These drive the real UI and the real endpoint — the plumbing is four hops (SQL → handler JSON →
 * store type → Svelte branch) and any one of them dropping the field restores the silent version.
 */
import { test, expect } from '../../fixtures/test';
import { BASE } from '../../helpers/env';

const SLUG = 'e2e-test-event';
const DISK_REASON =
  'Nicht genug Speicherplatz für das Keepsake: benötigt ca. 42.0 GB, frei sind 3.0 GB. ' +
  'Bitte Speicher freigeben und das Keepsake anschließend neu erstellen.';

test.describe('Export — a failed keepsake explains itself to the host', () => {
  test('the failure reason reaches /export/status', async ({ host, db }) => {
    await db.setExportReleased(SLUG, true);
    await db.fakeExportJob(SLUG, 'zip', 'failed', DISK_REASON);
    await db.fakeExportJob(SLUG, 'html', 'failed', DISK_REASON);

    const res = await fetch(`${BASE}/api/v1/export/status`, {
      headers: { Authorization: `Bearer ${host.jwt}` },
    });
    expect(res.status).toBe(200);
    const body = (await res.json()) as {
      zip: { status: string; error_message: string | null };
      html: { status: string; error_message: string | null };
    };

    expect(body.zip.status).toBe('failed');
    expect(
      body.zip.error_message,
      'the reason must travel with the status, not live only in the admin job list'
    ).toBe(DISK_REASON);
    expect(body.html.error_message).toBe(DISK_REASON);
  });

  test('a succeeding export carries no stale reason', async ({ host, db }) => {
    // The mirror that keeps the above honest: a handler that returned `error_message`
    // unconditionally would pass the first test while showing an error next to a green
    // "Keepsake ist bereit." Rows keep their last message until they are re-armed, so this is a
    // real state, not a hypothetical one.
    await db.setExportReleased(SLUG, true);
    await db.fakeExportJob(SLUG, 'zip', 'failed', DISK_REASON);
    await db.fakeExportJob(SLUG, 'zip', 'done', DISK_REASON);

    const res = await fetch(`${BASE}/api/v1/export/status`, {
      headers: { Authorization: `Bearer ${host.jwt}` },
    });
    const body = (await res.json()) as { zip: { status: string; error_message: string | null } };
    expect(body.zip.status).toBe('done');
    expect(
      body.zip.error_message,
      'a message left on a row that has since succeeded must not be shown'
    ).toBeNull();
  });

  test('the host dashboard renders the reason under the failure', async ({
    page,
    host,
    signIn,
    db,
  }) => {
    await db.setExportReleased(SLUG, true);
    await db.fakeExportJob(SLUG, 'zip', 'failed', DISK_REASON);
    await db.fakeExportJob(SLUG, 'html', 'failed', DISK_REASON);

    await signIn(page, host);
    await page.goto('/host');

    await expect(page.getByText(/Keepsake-Erstellung fehlgeschlagen/i)).toBeVisible({
      timeout: 15_000,
    });
    // The actionable half — the numbers, not just the verdict.
    await expect(
      page.getByText(/Nicht genug Speicherplatz/i),
      'the host must see WHY, next to the only button they have'
    ).toBeVisible();
    await expect(page.getByText(/3\.0 GB/)).toBeVisible();

    // And the retry button is still mounted — it is deliberately outside the status branches.
    await expect(page.getByTestId('export-rebuild')).toBeVisible();
  });
});
