import { beforeEach, describe, expect, it, vi } from 'vitest';
// Mock the SSRF-safe fetch so webhook "test" deliveries don't hit the network.
const safeFetchMock = vi.hoisted(() => vi.fn());
vi.mock('../../security/safe-fetch.js', () => ({
    safeFetch: (...args) => safeFetchMock(...args),
    SsrfBlockedError: class SsrfBlockedError extends Error {
    },
}));
import { handleActuateAPI } from '../../api/index.js';
import { createSession } from '../../auth/session.js';
import { initDB } from '../../db.js';
import { generateToken as generateCsrfToken } from '../../security/csrf.js';
const SECRET = 'test-secret-for-form-webhooks-1234567890abcd';
const FORM_ROW = {
    id: 'form-1',
    title: 'Contact Us',
    slug: 'contact-us',
    collection: 'forms',
    createdById: 'admin-1',
    createdAt: new Date('2026-01-01T00:00:00.000Z'),
    updatedAt: new Date('2026-01-02T00:00:00.000Z'),
    data: {
        name: 'Contact Us',
        slug: 'contact-us',
        status: 'active',
        activeSchemaVersionId: null,
        fields: [
            { id: '1', key: 'name', label: 'Name', type: 'text', required: true, sortOrder: 0 },
            { id: '2', key: 'email', label: 'Email', type: 'email', required: true, sortOrder: 1 },
        ],
    },
};
function createMockDB() {
    const webhooks = [];
    let counter = 0;
    const db = {
        webhooks,
        session: { findUnique: async () => ({ revokedAt: null }) },
        user: {},
        media: {},
        auditLog: { create: async () => ({}) },
        document: {
            findFirst: async (args) => {
                const where = args?.where ?? {};
                if (where.collection !== 'forms')
                    return null;
                if (where.id && where.id !== 'form-1')
                    return null;
                if (where.slug && where.slug !== 'contact-us')
                    return null;
                return FORM_ROW;
            },
        },
        formSubmission: { groupBy: async () => [], count: async () => 0 },
        formWebhook: {
            create: async ({ data }) => {
                counter += 1;
                const row = {
                    id: `wh-${counter}`,
                    createdAt: new Date(),
                    updatedAt: new Date(),
                    lastDeliveryAt: null,
                    lastDeliveryStatus: null,
                    ...data,
                };
                webhooks.push(row);
                return row;
            },
            findMany: async ({ where }) => webhooks.filter((w) => w.formId === where.formId),
            findUnique: async ({ where }) => webhooks.find((w) => w.id === where.id) ?? null,
            update: async ({ where, data }) => {
                const w = webhooks.find((x) => x.id === where.id);
                Object.assign(w, data);
                return w;
            },
            delete: async ({ where }) => {
                const i = webhooks.findIndex((x) => x.id === where.id);
                webhooks.splice(i, 1);
                return {};
            },
        },
    };
    return db;
}
async function adminHeaders() {
    const token = await createSession({ userId: 'admin-1', role: 'ADMIN', sessionId: 'sess-admin' }, { secret: SECRET });
    const csrf = await generateCsrfToken();
    return {
        cookie: `actuate_session=${token}; actuate_csrf=${csrf}`,
        'x-csrf-token': csrf,
        'content-type': 'application/json',
    };
}
describe('form webhook + notification endpoints', () => {
    let db;
    let handler;
    beforeEach(() => {
        process.env.CMS_SECRET = SECRET;
        safeFetchMock.mockReset();
        db = createMockDB();
        initDB(db);
        handler = handleActuateAPI({ prismaClient: db });
    });
    it('rejects unauthenticated webhook listing', async () => {
        const res = await handler(new Request('https://example.com/api/cms/forms/form-1/webhooks'));
        expect(res.status).toBe(401);
    });
    it('creates a webhook and returns the secret once, then masks it on list', async () => {
        const headers = await adminHeaders();
        const createRes = await handler(new Request('https://example.com/api/cms/forms/form-1/webhooks', {
            method: 'POST',
            headers,
            body: JSON.stringify({ url: 'https://hooks.example.com/x', events: ['form.submitted'] }),
        }));
        expect(createRes.status).toBe(201);
        const created = (await createRes.json());
        expect(created.data.secret).toMatch(/^whsec_/);
        expect(created.data.events).toEqual(['form.submitted']);
        const listRes = await handler(new Request('https://example.com/api/cms/forms/form-1/webhooks', {
            headers: { cookie: headers.cookie },
        }));
        expect(listRes.status).toBe(200);
        const list = (await listRes.json());
        expect(list.data).toHaveLength(1);
        expect(list.data[0].secret).toBeUndefined();
    });
    it('rejects an SSRF webhook URL with 400', async () => {
        const headers = await adminHeaders();
        const res = await handler(new Request('https://example.com/api/cms/forms/form-1/webhooks', {
            method: 'POST',
            headers,
            body: JSON.stringify({ url: 'http://localhost/hook' }),
        }));
        expect(res.status).toBe(400);
    });
    it('sends a test delivery through the webhook', async () => {
        safeFetchMock.mockResolvedValue({ ok: true, status: 200, text: async () => '' });
        const headers = await adminHeaders();
        const created = (await (await handler(new Request('https://example.com/api/cms/forms/form-1/webhooks', {
            method: 'POST',
            headers,
            body: JSON.stringify({ url: 'https://hooks.example.com/x' }),
        }))).json());
        const testRes = await handler(new Request(`https://example.com/api/cms/forms/form-1/webhooks/${created.data.id}/test`, {
            method: 'POST',
            headers,
        }));
        expect(testRes.status).toBe(200);
        const body = (await testRes.json());
        expect(body.data.ok).toBe(true);
        expect(safeFetchMock).toHaveBeenCalledTimes(1);
    });
    it('returns 400 from the test-notification route when no recipients are configured', async () => {
        const headers = await adminHeaders();
        const res = await handler(new Request('https://example.com/api/cms/forms/form-1/notifications/test', {
            method: 'POST',
            headers,
        }));
        expect(res.status).toBe(400);
    });
});
//# sourceMappingURL=form-webhooks.test.js.map