import { describe, it, expect } from 'vitest';
import { checkAccess, getPermissionsForRole, filterFieldsByRole, applyFieldAccess, } from '../../security/access.js';
describe('checkAccess', () => {
    it('ADMIN can access everything', () => {
        expect(checkAccess('ADMIN', 'ADMIN')).toBe(true);
        expect(checkAccess('ADMIN', 'EDITOR')).toBe(true);
        expect(checkAccess('ADMIN', 'AUTHOR')).toBe(true);
        expect(checkAccess('ADMIN', 'CLIENT')).toBe(true);
    });
    it('EDITOR can access AUTHOR level', () => {
        expect(checkAccess('EDITOR', 'AUTHOR')).toBe(true);
        expect(checkAccess('EDITOR', 'CLIENT')).toBe(true);
        expect(checkAccess('EDITOR', 'EDITOR')).toBe(true);
    });
    it('EDITOR cannot access ADMIN level', () => {
        expect(checkAccess('EDITOR', 'ADMIN')).toBe(false);
    });
    it('AUTHOR cannot access EDITOR level', () => {
        expect(checkAccess('AUTHOR', 'EDITOR')).toBe(false);
        expect(checkAccess('AUTHOR', 'ADMIN')).toBe(false);
    });
    it('AUTHOR can access AUTHOR and CLIENT levels', () => {
        expect(checkAccess('AUTHOR', 'AUTHOR')).toBe(true);
        expect(checkAccess('AUTHOR', 'CLIENT')).toBe(true);
    });
    it('CLIENT cannot access AUTHOR level', () => {
        expect(checkAccess('CLIENT', 'AUTHOR')).toBe(false);
        expect(checkAccess('CLIENT', 'EDITOR')).toBe(false);
        expect(checkAccess('CLIENT', 'ADMIN')).toBe(false);
    });
    it('CLIENT can access CLIENT level', () => {
        expect(checkAccess('CLIENT', 'CLIENT')).toBe(true);
    });
});
describe('getPermissionsForRole', () => {
    it('ADMIN gets delete permission', () => {
        const perms = getPermissionsForRole('ADMIN');
        const actions = perms.map((p) => p.action);
        expect(actions).toContain('delete');
        expect(actions).toContain('create');
        expect(actions).toContain('read');
        expect(actions).toContain('update');
        expect(actions).toContain('publish');
    });
    it('EDITOR gets publish but not delete', () => {
        const perms = getPermissionsForRole('EDITOR');
        const actions = perms.map((p) => p.action);
        expect(actions).toContain('publish');
        expect(actions).toContain('read');
        expect(actions).toContain('create');
        expect(actions).not.toContain('delete');
    });
    it('AUTHOR gets create but not delete', () => {
        const perms = getPermissionsForRole('AUTHOR');
        const actions = perms.map((p) => p.action);
        expect(actions).toContain('read');
        expect(actions).toContain('create');
        expect(actions).not.toContain('delete');
        expect(actions).not.toContain('publish');
    });
    it('CLIENT only gets read permission', () => {
        const perms = getPermissionsForRole('CLIENT');
        const actions = perms.map((p) => p.action);
        expect(actions).toEqual(['read']);
    });
    it('AUTHOR has "update own" but not "update *"', () => {
        const perms = getPermissionsForRole('AUTHOR');
        const updatePerms = perms.filter((p) => p.action === 'update');
        expect(updatePerms).toHaveLength(1);
        expect(updatePerms[0].resource).toBe('own');
    });
    it('EDITOR has "update *" (all resources)', () => {
        const perms = getPermissionsForRole('EDITOR');
        const updatePerms = perms.filter((p) => p.action === 'update');
        const resources = updatePerms.map((p) => p.resource);
        expect(resources).toContain('*');
    });
});
describe('filterFieldsByRole', () => {
    const adminUser = { id: 'admin-1', role: 'ADMIN' };
    const clientUser = { id: 'client-1', role: 'CLIENT' };
    it('returns all fields when no access control is defined', async () => {
        const fields = {
            title: { type: 'text', label: 'Title', required: true },
            body: { type: 'richText', label: 'Body' },
        };
        const filtered = await filterFieldsByRole(fields, clientUser);
        expect(Object.keys(filtered)).toEqual(['title', 'body']);
    });
    it('returns a shallow copy, not the same reference', async () => {
        const fields = {
            name: { type: 'text', label: 'Name' },
        };
        const filtered = await filterFieldsByRole(fields, adminUser);
        expect(filtered).not.toBe(fields);
        expect(filtered).toEqual(fields);
    });
    it('filters out fields the user cannot read', async () => {
        const fields = {
            title: { type: 'text', label: 'Title' },
            secret: {
                type: 'text',
                label: 'Secret',
                access: {
                    read: async ({ user }) => user?.role === 'ADMIN',
                },
            },
        };
        const clientFiltered = await filterFieldsByRole(fields, clientUser);
        expect(Object.keys(clientFiltered)).toEqual(['title']);
        const adminFiltered = await filterFieldsByRole(fields, adminUser);
        expect(Object.keys(adminFiltered)).toEqual(['title', 'secret']);
    });
});
describe('applyFieldAccess', () => {
    const adminUser = { id: 'admin-1', role: 'ADMIN' };
    const clientUser = { id: 'client-1', role: 'CLIENT' };
    it('read mode: strips fields the user cannot read', async () => {
        const fields = {
            title: { type: 'text', label: 'Title' },
            internal: {
                type: 'text',
                label: 'Internal',
                access: {
                    read: async ({ user }) => user?.role === 'ADMIN',
                },
            },
        };
        const data = { title: 'Hello', internal: 'secret-value', extra: 'kept' };
        const clientResult = await applyFieldAccess('read', fields, data, clientUser);
        expect(clientResult).toEqual({ title: 'Hello', extra: 'kept' });
        const adminResult = await applyFieldAccess('read', fields, data, adminUser);
        expect(adminResult).toEqual({ title: 'Hello', internal: 'secret-value', extra: 'kept' });
    });
    it('write mode: strips fields the user cannot update', async () => {
        const fields = {
            title: { type: 'text', label: 'Title' },
            locked: {
                type: 'text',
                label: 'Locked',
                access: {
                    update: async ({ user }) => user?.role === 'ADMIN',
                },
            },
        };
        const data = { title: 'New Title', locked: 'overwrite-attempt' };
        const clientResult = await applyFieldAccess('write', fields, data, clientUser);
        expect(clientResult).toEqual({ title: 'New Title' });
        const adminResult = await applyFieldAccess('write', fields, data, adminUser);
        expect(adminResult).toEqual({ title: 'New Title', locked: 'overwrite-attempt' });
    });
    it('passes through unknown keys on read', async () => {
        const fields = {
            title: { type: 'text', label: 'Title' },
        };
        const data = { title: 'Hello', unknownField: 'value' };
        const result = await applyFieldAccess('read', fields, data, clientUser);
        expect(result).toEqual({ title: 'Hello', unknownField: 'value' });
    });
    it('strips unknown keys on write (mass assignment prevention)', async () => {
        const fields = {
            title: { type: 'text', label: 'Title' },
        };
        const data = { title: 'Hello', isAdmin: true, role: 'ADMIN' };
        const result = await applyFieldAccess('write', fields, data, clientUser);
        expect(result).toEqual({ title: 'Hello' });
        expect(result).not.toHaveProperty('isAdmin');
        expect(result).not.toHaveProperty('role');
    });
    it('allows system keys on write', async () => {
        const fields = {
            body: { type: 'richText', label: 'Body' },
        };
        const data = { body: '<p>Hi</p>', title: 'My Page', slug: 'my-page', status: 'PUBLISHED' };
        const result = await applyFieldAccess('write', fields, data, clientUser);
        expect(result).toHaveProperty('title');
        expect(result).toHaveProperty('slug');
        expect(result).toHaveProperty('status');
    });
});
//# sourceMappingURL=access.test.js.map