import { beforeEach, describe, expect, it } from 'vitest';
import { handleActuateAPI } from '../../api/index.js';
import { initDB } from '../../db.js';
import { generateApiKey } from '../../security/api-key-enhanced.js';
/**
 * `GET /collections/:slug/field-values` — distinct in-use values for one
 * field, powering tag autocomplete and category suggestions in the admin.
 * Pins the vocabulary-merging contract: `AI` / `ai` / `Ai` count as ONE value
 * (first-seen casing wins), so editor suggestions never splinter a taxonomy.
 */
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 },
        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: async () => opts.docs ?? [],
            findFirst: async () => null,
            count: 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 request(handler, path, key) {
    return handler(new Request(`https://example.com/api/cms${path}`, {
        headers: { Authorization: `Bearer ${key}` },
    }));
}
describe('GET /collections/:slug/field-values', () => {
    beforeEach(() => {
        delete globalThis.__actuateConfig;
        process.env.CMS_SECRET = VALID_SECRET;
    });
    it('aggregates array tags case-insensitively across row and string shapes', async () => {
        const { key, record } = await makeKey({ collections: ['posts'], actions: ['read'] });
        const db = createMockDB({
            apiKey: record,
            docs: [
                { data: { tags: [{ tag: 'AI' }, { tag: 'CMS' }] } },
                // Older sites store plain strings; casing drift must merge into one value.
                { data: { tags: ['ai', 'Nextjs'] } },
                { data: { tags: [{ tag: 'AI' }] } },
                { data: { tags: 'not-an-array' } },
                { data: null },
            ],
        });
        initDB(db);
        const response = await request(makeHandler(db), '/collections/posts/field-values?field=tags', key);
        expect(response.status).toBe(200);
        const { data } = (await response.json());
        expect(data.field).toBe('tags');
        // 'AI' + 'ai' + 'AI' merge into one entry (3 uses), most-used first.
        expect(data.values[0]).toEqual({ value: 'AI', count: 3 });
        expect(data.values.map((v) => v.value)).toEqual(['AI', 'CMS', 'Nextjs']);
    });
    it('filters by ?q= substring, case-insensitively', async () => {
        const { key, record } = await makeKey({ collections: ['posts'], actions: ['read'] });
        const db = createMockDB({
            apiKey: record,
            docs: [{ data: { tags: [{ tag: 'Design' }, { tag: 'DevOps' }, { tag: 'Marketing' }] } }],
        });
        initDB(db);
        const response = await request(makeHandler(db), '/collections/posts/field-values?field=tags&q=de', key);
        const { data } = (await response.json());
        expect(data.values.map((v) => v.value).sort()).toEqual(['Design', 'DevOps']);
    });
    it('aggregates plain text fields like category', async () => {
        const { key, record } = await makeKey({ collections: ['posts'], actions: ['read'] });
        const db = createMockDB({
            apiKey: record,
            docs: [
                { data: { category: 'News' } },
                { data: { category: 'news' } },
                { data: { category: 'Tutorials' } },
                { data: { category: '' } },
            ],
        });
        initDB(db);
        const response = await request(makeHandler(db), '/collections/posts/field-values?field=category', key);
        const { data } = (await response.json());
        expect(data.values).toEqual([
            { value: 'News', count: 2 },
            { value: 'Tutorials', count: 1 },
        ]);
    });
    it('rejects undeclared or non-suggestible fields with 400', async () => {
        const { key, record } = await makeKey({ collections: ['posts'], actions: ['read'] });
        const db = createMockDB({ apiKey: record, docs: [] });
        initDB(db);
        const handler = makeHandler(db);
        for (const field of ['body', 'nope', '']) {
            const response = await request(handler, `/collections/posts/field-values?field=${field}`, key);
            expect(response.status).toBe(400);
        }
    });
    it('enforces collection read scope (403 for keys scoped elsewhere)', async () => {
        const { key, record } = await makeKey({ collections: ['pages'], actions: ['read'] });
        const db = createMockDB({ apiKey: record, docs: [] });
        initDB(db);
        const response = await request(makeHandler(db), '/collections/posts/field-values?field=tags', key);
        expect(response.status).toBe(403);
    });
});
//# sourceMappingURL=field-values-routes.test.js.map