/**
 * USER_JOURNEYS.md §6 + §18 — upload rate limit and the admin toggle.
 *
 * Re-enables rate limits at the top of the file, restores them at the bottom
 * (global-setup has them off for the rest of the suite).
 */
import { test, expect } from '../../fixtures/test';
import { join } from 'node:path';
import { readFileSync } from 'node:fs';

const SAMPLE_JPG = join(process.cwd(), 'fixtures', 'media', 'sample.jpg');
// A real, decodable JPEG — the upload handler validates magic bytes, so a
// zero-filled buffer would be rejected with 400 before the rate limiter is reached.
const SAMPLE_BYTES = readFileSync(SAMPLE_JPG);

test.describe('Upload — rate limit', () => {
  test('4th upload in one hour returns 429 with Retry-After', async ({
    api,
    adminToken,
    guest,
  }) => {
    // Enable inside the test body, AFTER all auto-fixtures (truncate) have run,
    // so the config can't be reset out from under us by the ordering of hooks
    // vs fixtures.
    await api.patchConfig(adminToken, {
      rate_limits_enabled: 'true',
      upload_rate_enabled: 'true',
      upload_rate_per_hour: '3',
    });
    const h = await guest('Quota');

    // Hit the API directly for speed — UI behavior is asserted in gallery-path.spec.
    const upload = async (n: number) => {
      const form = new FormData();
      const blob = new Blob([SAMPLE_BYTES], { type: 'image/jpeg' });
      form.append('file', blob, `file${n}.jpg`);
      form.append('content_type', 'image/jpeg');
      return fetch((process.env.E2E_FRONTEND_URL ?? 'http://localhost:3101') + '/api/v1/upload', {
        method: 'POST',
        headers: { Authorization: `Bearer ${h.jwt}` },
        body: form,
      });
    };

    // 4 parallel uploads with limit=3 → exactly one returns 429, but Promise.all
    // preserves request-issue order, not server-execution order. Assert by count
    // (3 accepted, 1 rate-limited) rather than position.
    const responses = await Promise.all([1, 2, 3, 4].map(upload));
    const statuses = responses.map((r) => r.status);
    const okCount = statuses.filter((s) => s === 201).length;
    const limitedCount = statuses.filter((s) => s === 429).length;
    expect(okCount).toBe(3);
    expect(limitedCount).toBe(1);

    // The 429 response carries Retry-After.
    const limited = responses.find((r) => r.status === 429)!;
    expect(limited.headers.get('retry-after')).toBeTruthy();
  });

  test('flipping upload_rate_enabled off bypasses the limit', async ({
    api,
    adminToken,
    guest,
  }) => {
    await api.patchConfig(adminToken, { upload_rate_enabled: 'false' });

    const h = await guest('NoQuota');
    const upload = async (n: number) => {
      const form = new FormData();
      const blob = new Blob([SAMPLE_BYTES], { type: 'image/jpeg' });
      form.append('file', blob, `file${n}.jpg`);
      form.append('content_type', 'image/jpeg');
      return fetch((process.env.E2E_FRONTEND_URL ?? 'http://localhost:3101') + '/api/v1/upload', {
        method: 'POST',
        headers: { Authorization: `Bearer ${h.jwt}` },
        body: form,
      });
    };
    const responses = await Promise.all([1, 2, 3, 4, 5].map(upload));
    expect(responses.some((r) => r.status === 429)).toBe(false);

    // Restore enabled for the next test in this file.
    await api.patchConfig(adminToken, { upload_rate_enabled: 'true' });
  });
});
