// @vitest-environment node
import { afterEach, describe, expect, it, vi } from 'vitest';
// Mock the network layer so we can assert on request shape (endpoint,
// method, body) and drive responses. This is the class of bug — response
// unwrapping and write-payload drift — these tests exist to catch.
const cmsApi = vi.fn();
vi.mock('../../lib/api.js', () => ({
    cmsApi: (...args) => cmsApi(...args),
}));
const { fetchPageForEditor, savePageDraft, publishPage, missingPageFields, emptyPage } = await import('../../lib/page-editor-service.js');
afterEach(() => {
    cmsApi.mockReset();
});
function draft(id) {
    return {
        ...emptyPage(),
        id,
        title: 'About',
        slug: 'about',
        path: '/about',
        seoTitle: 'About us',
        seoDescription: 'Our story',
        sections: [],
    };
}
describe('fetchPageForEditor', () => {
    it('maps a document row into an EditorPage', async () => {
        cmsApi.mockResolvedValue({
            data: {
                id: 'p1',
                title: 'About',
                slug: 'about',
                status: 'PUBLISHED',
                publishedAt: '2026-01-02T00:00:00Z',
                updatedAt: '2026-01-03T00:00:00Z',
                data: { path: '/about', sections: [], metaTitle: 'T', metaDescription: 'D' },
            },
            status: 200,
        });
        const page = await fetchPageForEditor('p1');
        expect(cmsApi).toHaveBeenCalledWith('/collections/pages/p1');
        expect(page).toMatchObject({
            id: 'p1',
            title: 'About',
            slug: 'about',
            path: '/about',
            status: 'PUBLISHED',
            seoTitle: 'T',
            seoDescription: 'D',
        });
    });
    it('falls back to /slug for path when data.path is absent', async () => {
        cmsApi.mockResolvedValue({
            data: { id: 'p2', title: 'Home', slug: 'home', status: 'DRAFT', data: {} },
            status: 200,
        });
        const page = await fetchPageForEditor('p2');
        expect(page.path).toBe('/home');
    });
    it('throws the server error message on failure', async () => {
        cmsApi.mockResolvedValue({ error: 'Document not found', status: 404 });
        await expect(fetchPageForEditor('missing')).rejects.toThrow('Document not found');
    });
});
describe('savePageDraft', () => {
    it('PUTs sections + SEO without a status change for an existing page', async () => {
        cmsApi.mockResolvedValue({
            data: { id: 'p1', title: 'About', slug: 'about', status: 'DRAFT', data: { sections: [] } },
            status: 200,
        });
        await savePageDraft(draft('p1'));
        const [endpoint, opts] = cmsApi.mock.calls[0];
        expect(endpoint).toBe('/collections/pages/p1');
        expect(opts.method).toBe('PUT');
        const body = JSON.parse(opts.body);
        expect(body).toMatchObject({
            title: 'About',
            slug: 'about',
            path: '/about',
            sections: [],
            metaTitle: 'About us',
            metaDescription: 'Our story',
        });
        // Draft save must never flip status.
        expect('status' in body).toBe(false);
    });
    it('creates (POST) a new page when there is no id', async () => {
        cmsApi.mockResolvedValue({
            data: { id: 'new1', title: 'About', slug: 'about', status: 'DRAFT', data: {} },
            status: 201,
        });
        const saved = await savePageDraft(draft(null));
        const [endpoint, opts] = cmsApi.mock.calls[0];
        expect(endpoint).toBe('/collections/pages');
        expect(opts.method).toBe('POST');
        expect(saved.id).toBe('new1');
    });
    it('throws when the server rejects the write', async () => {
        cmsApi.mockResolvedValue({ error: 'Forbidden', status: 403 });
        await expect(savePageDraft(draft('p1'))).rejects.toThrow('Forbidden');
    });
});
describe('publishPage', () => {
    it('includes status: PUBLISHED in the payload', async () => {
        cmsApi.mockResolvedValue({
            data: { id: 'p1', title: 'About', slug: 'about', status: 'PUBLISHED', data: {} },
            status: 200,
        });
        await publishPage(draft('p1'));
        const [, opts] = cmsApi.mock.calls[0];
        const body = JSON.parse(opts.body);
        expect(body.status).toBe('PUBLISHED');
    });
});
describe('missingPageFields', () => {
    const fullFields = {
        title: { type: 'text' },
        slug: { type: 'slug' },
        path: { type: 'text' },
        sections: { type: 'json' },
        metaTitle: { type: 'text' },
        metaDescription: { type: 'text' },
    };
    it('returns [] when no config is provided', () => {
        expect(missingPageFields(undefined)).toEqual([]);
        expect(missingPageFields(null)).toEqual([]);
        expect(missingPageFields({})).toEqual([]);
    });
    it('returns [] when the pages collection declares every required field (record form)', () => {
        const config = { collections: { pages: { slug: 'pages', fields: fullFields } } };
        expect(missingPageFields(config)).toEqual([]);
    });
    it('reports the missing required fields', () => {
        const config = {
            collections: {
                pages: { slug: 'pages', fields: { title: { type: 'text' }, slug: { type: 'slug' } } },
            },
        };
        expect(missingPageFields(config)).toEqual(['sections', 'path', 'metaTitle', 'metaDescription']);
    });
    it('supports the array form of field definitions', () => {
        const config = {
            collections: [
                { slug: 'pages', fields: Object.entries(fullFields).map(([name, f]) => ({ name, ...f })) },
            ],
        };
        expect(missingPageFields(config)).toEqual([]);
    });
    it('flags a pages collection that omits sections (data-loss guard)', () => {
        const { sections: _omitted, ...withoutSections } = fullFields;
        const config = { collections: { pages: { slug: 'pages', fields: withoutSections } } };
        expect(missingPageFields(config)).toEqual(['sections']);
    });
});
//# sourceMappingURL=page-editor-service-api.test.js.map