import { beforeEach, describe, expect, it, vi } from 'vitest';
import { handleActuateAPI } from '../../api/index.js';
import { initDB } from '../../db.js';
import { generateApiKey } from '../../security/api-key-enhanced.js';
/**
 * `GET /collections/:slug?filter.<field>=<value>` — admin facet filters
 * (taxonomy Phase B). Pins the Prisma JSON `where` contract: scalar fields
 * filter with `path`/`equals`, tag-shaped arrays match BOTH the canonical
 * `[{ tag }]` row shape and legacy plain-string arrays, and undeclared or
 * long-form fields are silently dropped (a stale URL must never 500 a list).
 */
const VALID_SECRET = 'a'.repeat(48);
const POSTS_COLLECTION = {
    slug: 'posts',
    labels: { singular: 'Post', plural: 'Posts' },
    fields: {
        title: { type: 'text', label: 'Title' },
        category: { type: 'text', label: 'Category', maxLength: 80 },
        topic: {
            type: 'select',
            label: 'Topic',
            options: [{ label: 'News', value: 'news' }],
        },
        body: { type: 'richText', label: 'Body' },
        tags: {
            type: 'array',
            label: 'Tags',
            maxRows: 12,
            fields: { tag: { type: 'text', label: 'Tag', required: true, maxLength: 40 } },
        },
    },
};
function createMockDB(opts) {
    return {
        apiKey: {
            findMany: async () => (opts.apiKey ? [opts.apiKey] : []),
            findUnique: async ({ where }) => opts.apiKey && opts.apiKey.keyHash === where.keyHash ? opts.apiKey : null,
            update: async () => opts.apiKey,
        },
        document: {
            findMany: vi.fn(async () => []),
            findFirst: async () => null,
            count: vi.fn(async () => 0),
        },
        user: {},
        session: {},
        media: {},
    };
}
async function makeKey(scopes) {
    const { key, keyHash, keyPrefix } = await generateApiKey({ prefix: 'act_sk', scopes });
    return {
        key,
        record: {
            id: 'apikey-1',
            keyHash,
            keyPrefix,
            userId: 'user-1',
            scopes,
            ipRestrictions: null,
            expiresAt: null,
            lastUsedAt: null,
            revokedAt: null,
        },
    };
}
function makeHandler(db) {
    return handleActuateAPI({
        prismaClient: db,
        config: { collections: { posts: POSTS_COLLECTION } },
    });
}
async function listRequest(db, key, query) {
    const handler = makeHandler(db);
    const response = await handler(new Request(`https://example.com/api/cms/collections/posts${query}`, {
        headers: { Authorization: `Bearer ${key}` },
    }));
    return response;
}
describe('GET /collections/:slug with filter.<field> params', () => {
    beforeEach(() => {
        delete globalThis.__actuateConfig;
        process.env.CMS_SECRET = VALID_SECRET;
    });
    it('builds scalar equals + dual-shape array containment in the where clause', async () => {
        const { key, record } = await makeKey({ collections: ['posts'], actions: ['read'] });
        const db = createMockDB({ apiKey: record });
        initDB(db);
        const response = await listRequest(db, key, '?filter.category=News&filter.tags=AI');
        expect(response.status).toBe(200);
        const where = db.document.findMany.mock.calls[0][0].where;
        expect(where.AND).toEqual([
            { data: { path: ['category'], equals: 'News' } },
            {
                OR: [
                    { data: { path: ['tags'], array_contains: [{ tag: 'AI' }] } },
                    { data: { path: ['tags'], array_contains: ['AI'] } },
                ],
            },
        ]);
        // count() must see the same filters or pagination totals drift.
        expect(db.document.count.mock.calls[0][0].where.AND).toEqual(where.AND);
    });
    it('filters select fields by stored value', async () => {
        const { key, record } = await makeKey({ collections: ['posts'], actions: ['read'] });
        const db = createMockDB({ apiKey: record });
        initDB(db);
        await listRequest(db, key, '?filter.topic=news');
        const where = db.document.findMany.mock.calls[0][0].where;
        expect(where.AND).toEqual([{ data: { path: ['topic'], equals: 'news' } }]);
    });
    it('silently drops undeclared, long-form, and empty filters', async () => {
        const { key, record } = await makeKey({ collections: ['posts'], actions: ['read'] });
        const db = createMockDB({ apiKey: record });
        initDB(db);
        const response = await listRequest(db, key, '?filter.body=hack&filter.nope=x&filter.category=%20%20');
        expect(response.status).toBe(200);
        const where = db.document.findMany.mock.calls[0][0].where;
        expect(where.AND).toBeUndefined();
    });
    it('leaves the where clause untouched when no filter params are present', async () => {
        const { key, record } = await makeKey({ collections: ['posts'], actions: ['read'] });
        const db = createMockDB({ apiKey: record });
        initDB(db);
        await listRequest(db, key, '?page=1');
        const where = db.document.findMany.mock.calls[0][0].where;
        expect(where.AND).toBeUndefined();
        expect(where).toMatchObject({ collection: 'posts', deletedAt: null });
    });
});
//# sourceMappingURL=data-filters-routes.test.js.map