import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { updateDocumentSeoFields } from '../../actions.js';
import { setActuateConfig } from '../../config/runtime.js';
/**
 * Regression tests for the `PUT /seo/content` data-layer blocker. SEO edits
 * must run through the data layer so they:
 *   - honor per-collection `access.update` (no cross-collection writes),
 *   - snapshot a Version row (audit trail), and
 *   - preserve undeclared SEO convention keys (canonical, og*, …) that the
 *     generic field-access layer would strip.
 */
function createMockDB(existing) {
    const versions = [];
    let current = existing
        ? { id: 'doc-1', collection: 'pages', data: existing, deletedAt: null }
        : null;
    return {
        document: {
            findFirst: vi.fn(async ({ where }) => {
                if (!current)
                    return null;
                if (where.id && current.id !== where.id)
                    return null;
                if (where.collection && current.collection !== where.collection)
                    return null;
                return current;
            }),
        },
        version: { create: vi.fn(async ({ data }) => ({ id: `v-${versions.length}`, ...data })) },
        $transaction: vi.fn(async (fn) => fn({
            document: {
                update: vi.fn(async ({ data }) => {
                    current = { ...current, ...data };
                    return current;
                }),
            },
            version: {
                create: vi.fn(async ({ data }) => {
                    const v = { id: `v-${versions.length}`, ...data };
                    versions.push(v);
                    return v;
                }),
            },
        })),
        _versions: versions,
    };
}
function ctxFor(db, role = 'ADMIN') {
    return { userId: 'user-1', role, db };
}
describe('updateDocumentSeoFields', () => {
    beforeEach(() => {
        setActuateConfig({});
    });
    afterEach(() => {
        setActuateConfig({});
    });
    it('merges SEO fields while preserving existing + undeclared keys', async () => {
        const db = createMockDB({ title: 'About', body: 'Original body' });
        const result = await updateDocumentSeoFields('pages', 'doc-1', { canonical: 'https://example.com/about', ogTitle: 'About Us', metaTitle: 'About' }, ctxFor(db));
        const data = (result.data ?? {});
        expect(data.title).toBe('About');
        expect(data.body).toBe('Original body');
        expect(data.canonical).toBe('https://example.com/about');
        expect(data.ogTitle).toBe('About Us');
        expect(data.metaTitle).toBe('About');
    });
    it('snapshots a Version row on update (audit trail)', async () => {
        const db = createMockDB({ title: 'About' });
        await updateDocumentSeoFields('pages', 'doc-1', { metaTitle: 'About' }, ctxFor(db));
        expect(db._versions.length).toBe(1);
        expect(db._versions[0]).toMatchObject({ documentId: 'doc-1', changeType: 'UPDATE' });
    });
    it('throws for a non-existent document', async () => {
        const db = createMockDB(null);
        await expect(updateDocumentSeoFields('pages', 'missing', { metaTitle: 'x' }, ctxFor(db))).rejects.toThrow('not found');
    });
    it('enforces the collection update access rule (no cross-collection writes)', async () => {
        setActuateConfig({
            collections: {
                pages: {
                    slug: 'pages',
                    labels: { singular: 'Page', plural: 'Pages' },
                    fields: {},
                    access: { update: () => false },
                },
            },
        });
        const db = createMockDB({ title: 'About' });
        await expect(updateDocumentSeoFields('pages', 'doc-1', { metaTitle: 'x' }, ctxFor(db, 'AUTHOR'))).rejects.toThrow('Access denied');
    });
});
//# sourceMappingURL=seo-fields-update.test.js.map