import { GraphQLError } from 'graphql';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { apiKeysResolvers } from '../resolvers/api-keys.resolver.js';
import { ApiKeysProvider } from '../providers/api-keys.provider.js';
const generateApiKeyResolver = apiKeysResolvers.Mutation?.generateApiKey;
const mockInfo = {};
describe('generateApiKey mutation', () => {
    let mockAuthProvider;
    let mockDb;
    let mockAuditProvider;
    let apiKeysProvider;
    beforeEach(() => {
        mockAuthProvider = {
            getAuthContext: vi.fn().mockResolvedValue({
                authType: 'jwt',
                token: 'token',
                user: {
                    userId: 'owner-user-id',
                    roleId: 'business_owner',
                    email: 'owner@example.com',
                    auth0UserId: 'auth0|owner-user-id',
                    permissions: [],
                    emailVerified: true,
                    permissionsVersion: 1,
                },
                tenant: {
                    businessId: 'business-123',
                    roleId: 'business_owner',
                },
            }),
        };
        mockDb = {
            query: vi.fn().mockResolvedValue({
                rowCount: 1,
                rows: [
                    {
                        id: 'api-key-id-1',
                        name: 'nightly scraper key',
                        role_id: 'scraper',
                        last_used_at: null,
                        created_at: new Date('2030-01-01T00:00:00.000Z'),
                    },
                ],
            }),
            transaction: vi.fn().mockImplementation(async (callback) => callback(mockDb)),
        };
        mockAuditProvider = {
            log: vi.fn().mockResolvedValue(undefined),
        };
        apiKeysProvider = new ApiKeysProvider(mockDb, mockAuthProvider, mockAuditProvider);
    });
    afterEach(() => {
        vi.clearAllMocks();
    });
    function createContext() {
        return {
            injector: {
                get(token) {
                    if (token === ApiKeysProvider) {
                        return apiKeysProvider;
                    }
                    throw new Error(`Unexpected token requested: ${String(token)}`);
                },
            },
        };
    }
    it('business_owner can generate API key', async () => {
        const result = await generateApiKeyResolver({}, { name: 'nightly scraper key', roleId: 'scraper' }, createContext(), mockInfo);
        expect(result.record).toEqual({
            id: 'api-key-id-1',
            name: 'nightly scraper key',
            roleId: 'scraper',
            lastUsedAt: null,
            createdAt: new Date('2030-01-01T00:00:00.000Z'),
        });
        expect(result.apiKey).toMatch(/^[a-f0-9]{128}$/);
    });
    it('plaintext key is 128 hex characters', async () => {
        const result = await generateApiKeyResolver({}, { name: 'automation key', roleId: 'scraper' }, createContext(), mockInfo);
        expect(result.apiKey).toHaveLength(128);
        expect(result.apiKey).toMatch(/^[a-f0-9]{128}$/);
    });
    it('stores SHA-256 hash in database (not plaintext)', async () => {
        const result = await generateApiKeyResolver({}, { name: 'finance sync key', roleId: 'scraper' }, createContext(), mockInfo);
        expect(mockDb.query).toHaveBeenCalledTimes(1);
        const [, params] = mockDb.query.mock.calls[0];
        const storedHash = params[2];
        expect(storedHash).toMatch(/^[a-f0-9]{64}$/);
        expect(storedHash).not.toBe(result.apiKey);
        expect(params).not.toContain(result.apiKey);
    });
    it('rejects invalid roleIds for API keys', async () => {
        const INVALID_ROLES = ['business_owner', 'employee', 'accountant'];
        for (const roleId of INVALID_ROLES) {
            await expect(generateApiKeyResolver({}, { name: 'forbidden key', roleId }, createContext(), mockInfo)).rejects.toSatisfy(error => {
                return error instanceof GraphQLError && error.extensions?.code === 'INVALID_ARGUMENT';
            });
            expect(mockDb.query).not.toHaveBeenCalled();
            expect(mockAuditProvider.log).not.toHaveBeenCalled();
        }
    });
    it('API key returned only in response (not stored in plaintext)', async () => {
        const result = await generateApiKeyResolver({}, { name: 'audit-safe key', roleId: 'scraper' }, createContext(), mockInfo);
        expect(mockAuditProvider.log).toHaveBeenCalledTimes(1);
        const auditEvent = mockAuditProvider.log.mock.calls[0][0];
        expect(JSON.stringify(auditEvent)).not.toContain(result.apiKey);
    });
    it('creates API_KEY_CREATED audit log entry', async () => {
        await generateApiKeyResolver({}, { name: 'logging key', roleId: 'scraper' }, createContext(), mockInfo);
        expect(mockAuditProvider.log).toHaveBeenCalledTimes(1);
        expect(mockAuditProvider.log.mock.calls[0][0]).toEqual(expect.objectContaining({
            action: 'API_KEY_CREATED',
            entity: 'ApiKey',
            entityId: 'api-key-id-1',
            ownerId: 'business-123',
            userId: 'owner-user-id',
            auth0UserId: 'auth0|owner-user-id',
        }));
    });
});
//# sourceMappingURL=generate-api-key.test.js.map