/**
 * RED-GREEN tests for the production Resend + Twilio adapters (W1.10).
 *
 * @connexum/ai-governance  F-NEW-PRODUCT-APPROVAL-CHANNEL-EMAIL-SMS
 */
import { describe, it } from 'node:test';
import * as assert from 'node:assert/strict';
import { createResendEmailSender, createTwilioSmsSender, } from './approval-channel-adapters.js';
function recordingTransport(response = { status: 200, bodyText: '{"id":"msg_1"}' }) {
    const calls = [];
    return {
        calls,
        transport: async (req) => {
            calls.push(req);
            return response;
        },
    };
}
describe('Resend email adapter (W1.10 production wiring)', () => {
    it('sends a POST to api.resend.com/emails with the right headers + body', async () => {
        const t = recordingTransport();
        const sender = createResendEmailSender({ apiKey: 're_sk_test', transport: t.transport });
        const res = await sender.send({
            to: 'reviewer@example.com',
            subject: 'Approval needed',
            html: '<p>Hi</p>',
            text: 'Hi',
        });
        assert.equal(res.ok, true);
        assert.equal(res.messageId, 'msg_1');
        assert.equal(t.calls.length, 1);
        const call = t.calls[0];
        assert.equal(call.method, 'POST');
        assert.equal(call.hostname, 'api.resend.com');
        assert.equal(call.path, '/emails');
        assert.equal(call.headers['authorization'], 'Bearer re_sk_test');
        assert.equal(call.headers['content-type'], 'application/json');
        const body = JSON.parse(call.body ?? '{}');
        assert.deepEqual(body.to, ['reviewer@example.com']);
        assert.equal(body.subject, 'Approval needed');
        assert.equal(body.html, '<p>Hi</p>');
    });
    it('non-2xx response surfaces as delivered=false with status + body in error', async () => {
        const t = recordingTransport({ status: 401, bodyText: '{"error":"Unauthorized"}' });
        const sender = createResendEmailSender({ apiKey: 're_sk_bad', transport: t.transport });
        const res = await sender.send({ to: 'r@e.com', subject: 's', html: '', text: '' });
        assert.equal(res.ok, false);
        assert.match(res.error ?? '', /status=401/);
    });
    it('transport throw surfaces as delivered=false with error message', async () => {
        const sender = createResendEmailSender({
            apiKey: 're_sk_test',
            transport: async () => {
                throw new Error('network down');
            },
        });
        const res = await sender.send({ to: 'r@e.com', subject: 's', html: '', text: '' });
        assert.equal(res.ok, false);
        assert.match(res.error ?? '', /network down/);
    });
    it('honors fromAddress override', async () => {
        const t = recordingTransport();
        const sender = createResendEmailSender({
            apiKey: 're_sk_test',
            transport: t.transport,
            fromAddress: 'compliance@acme.com',
        });
        await sender.send({ to: 'r@e.com', subject: 's', html: 'x', text: 'x' });
        const body = JSON.parse(t.calls[0].body ?? '{}');
        assert.equal(body.from, 'compliance@acme.com');
    });
    it('missing apiKey throws on construction', () => {
        assert.throws(() => createResendEmailSender({ apiKey: '' }), /apiKey is required/);
    });
});
describe('Twilio SMS adapter (W1.10 production wiring)', () => {
    it('sends a POST to Twilio Messages endpoint with basic auth + form body', async () => {
        const t = recordingTransport({
            status: 201,
            bodyText: '{"sid":"SM123","status":"queued"}',
        });
        const sender = createTwilioSmsSender({
            accountSid: 'AC123',
            authToken: 'tok',
            from: '+15551112222',
            transport: t.transport,
        });
        const res = await sender.send({ to: '+15553334444', body: 'Approve: https://x' });
        assert.equal(res.ok, true);
        assert.equal(res.messageId, 'SM123');
        const call = t.calls[0];
        assert.equal(call.method, 'POST');
        assert.equal(call.hostname, 'api.twilio.com');
        assert.equal(call.path, '/2010-04-01/Accounts/AC123/Messages.json');
        assert.match(call.headers['authorization'], /^Basic /);
        assert.equal(call.headers['content-type'], 'application/x-www-form-urlencoded');
        const form = new URLSearchParams(call.body ?? '');
        assert.equal(form.get('From'), '+15551112222');
        assert.equal(form.get('To'), '+15553334444');
        assert.equal(form.get('Body'), 'Approve: https://x');
    });
    it('uses MessagingServiceSid when from starts with MG', async () => {
        const t = recordingTransport({ status: 201, bodyText: '{"sid":"SM2"}' });
        const sender = createTwilioSmsSender({
            accountSid: 'AC123',
            authToken: 'tok',
            from: 'MGabc123',
            transport: t.transport,
        });
        await sender.send({ to: '+15553334444', body: 'x' });
        const form = new URLSearchParams(t.calls[0].body ?? '');
        assert.equal(form.get('MessagingServiceSid'), 'MGabc123');
        assert.equal(form.get('From'), null);
    });
    it('non-2xx response surfaces as delivered=false with status + body', async () => {
        const t = recordingTransport({ status: 400, bodyText: '{"code":21211}' });
        const sender = createTwilioSmsSender({
            accountSid: 'AC123',
            authToken: 'tok',
            from: '+15551112222',
            transport: t.transport,
        });
        const res = await sender.send({ to: 'bad', body: 'x' });
        assert.equal(res.ok, false);
        assert.match(res.error ?? '', /status=400/);
    });
    it('missing accountSid / authToken / from throws on construction', () => {
        assert.throws(() => createTwilioSmsSender({ accountSid: '', authToken: 't', from: '+1' }), /accountSid.*required/i);
        assert.throws(() => createTwilioSmsSender({ accountSid: 'AC', authToken: '', from: '+1' }), /authToken.*required/i);
        assert.throws(() => createTwilioSmsSender({ accountSid: 'AC', authToken: 't', from: '' }), /from.*required/i);
    });
});
describe('Adapters integrate with ApprovalChannelDispatcher', () => {
    it('end-to-end: dispatcher -> Resend adapter -> outcome.delivered=true', async () => {
        const { ApprovalChannelDispatcher } = await import('./approval-notifications.js');
        const t = recordingTransport();
        const dispatcher = new ApprovalChannelDispatcher({
            emailSender: createResendEmailSender({ apiKey: 're_sk', transport: t.transport }),
        });
        const outcomes = await dispatcher.dispatch({
            ticketId: 'tic-1',
            orgId: 'org-x',
            agentId: 'agent-1',
            toolName: 'Bash',
            riskLevel: 'high',
            summary: 'destructive shell call',
            approveUrl: 'https://my-cc.io/approve/tic-1',
            denyUrl: 'https://my-cc.io/deny/tic-1',
            slaDeadline: '2026-05-12T15:00:00.000Z',
        }, [
            {
                reviewerId: 'r1',
                name: 'Reviewer',
                email: 'r1@example.com',
                channels: ['email'],
            },
        ]);
        assert.equal(outcomes[0].delivered, true);
        assert.equal(outcomes[0].providerMessageId, 'msg_1');
        assert.equal(t.calls.length, 1);
    });
});
//# sourceMappingURL=approval-channel-adapters.test.js.map