/**
 * The gallery assembler with the repository mocked. Asserts the response is
 * self-consistent against the frontend's own schema (PLANNING.md §12 — "the
 * single highest-value test in the repo"). The DB-backed version of this check
 * lives in test/public-api.test.ts.
 */
import { beforeEach, describe, expect, it, vi } from 'vitest';

vi.mock('./media.repository', () => ({
  listReadyImages: vi.fn(),
  listVariants: vi.fn(),
}));

import { spaceGallerySchema } from '../../types/contract';
import { listReadyImages, listVariants } from './media.repository';
import { getSpaceGallery } from './gallery.service';

const img = (id: string, position: number) => ({
  id,
  page: 'genesis' as const,
  category_id: 1,
  alt: `Office ${position}`,
  caption: 'Office',
  position,
  width: 1600,
  height: 1066,
  updated_at: `2026-09-0${position} 03:00:00`,
});

const variantsFor = (id: string) => [
  {
    image_id: id,
    format: 'avif' as const,
    width: 1024,
    height: 682,
    path: `genesis/${id}/1024.avif`,
    is_primary: 0,
  },
  {
    image_id: id,
    format: 'avif' as const,
    width: 640,
    height: 426,
    path: `genesis/${id}/640.avif`,
    is_primary: 0,
  },
  {
    image_id: id,
    format: 'webp' as const,
    width: 640,
    height: 426,
    path: `genesis/${id}/640.webp`,
    is_primary: 0,
  },
  {
    image_id: id,
    format: 'jpeg' as const,
    width: 1600,
    height: 1066,
    path: `genesis/${id}/1600.jpg`,
    is_primary: 1,
  },
];

beforeEach(() => vi.clearAllMocks());

describe('getSpaceGallery', () => {
  it('assembles a contract-valid SpaceGallery', async () => {
    vi.mocked(listReadyImages).mockResolvedValue([img('a', 1), img('b', 2)]);
    vi.mocked(listVariants).mockResolvedValue([...variantsFor('a'), ...variantsFor('b')]);

    const gallery = await getSpaceGallery('genesis');

    // does not throw
    spaceGallerySchema.parse(gallery);

    expect(gallery.slug).toBe('genesis');
    expect(gallery.updatedAt).toBe('2026-09-02T03:00:00.000Z'); // MAX(updated_at), ISO-Z
    expect(gallery.images.map((i) => i.order)).toEqual([1, 2]);
    expect(gallery.images[0].src).toBe('http://localhost:4000/media/genesis/a/1600.jpg');
    expect(gallery.images[0].variants.avif.map((v) => v.width)).toEqual([640, 1024]); // ascending
  });

  it('rejects an unknown slug', async () => {
    await expect(getSpaceGallery('nope')).rejects.toMatchObject({ status: 404 });
  });

  it('returns an empty array (200) for a space with no images — no throw', async () => {
    vi.mocked(listReadyImages).mockResolvedValue([]);
    vi.mocked(listVariants).mockResolvedValue([]);

    const gallery = await getSpaceGallery('hive');
    expect(gallery.images).toEqual([]);
    expect(gallery.updatedAt).toMatch(/\dT\d.*Z$/);
  });

  it('passes a category filter through to the repository', async () => {
    vi.mocked(listReadyImages).mockResolvedValue([]);
    vi.mocked(listVariants).mockResolvedValue([]);
    await getSpaceGallery('genesis', 'office');
    expect(listReadyImages).toHaveBeenCalledWith('genesis', 'office');
  });
});
