/**
 * Microsoft Teams Channel (PR-27 / P3-10, May 2026).
 *
 * Posts to a Teams Incoming Webhook. The operator creates the webhook
 * on the Teams channel (Channel > Connectors > Incoming Webhook >
 * Create) and stores the URL in this channel's encrypted config.
 *
 * Config shape (ChannelConfig.teams):
 *   { webhookUrl: string, title?: string }
 *
 * Body uses the simple "text" form; richer Adaptive Card / MessageCard
 * formats are a follow-up if the operator wants click-through actions.
 */
import type { NotificationChannel, ChannelConfig } from '../types';
import { log } from '@/lib/observability/logger';
import { captureException } from '@/lib/observability/sentry';
import { safeOutboundFetch } from '@/lib/network-security/safe-fetch';
import { redactHighEntropy } from '../redact';

export class TeamsChannel implements NotificationChannel {
    readonly type = 'teams' as const;

    async send(message: string, config: ChannelConfig): Promise<void> {
        try {
            await this.sendOrThrow(message, config);
        } catch (error) {
            log.error({ err: error, channel: 'teams' }, 'TeamsChannel send failed');
            captureException(error, { channel: 'teams' });
        }
    }

    async sendOrThrow(message: string, config: ChannelConfig): Promise<void> {
        const webhookUrl = (config as { webhookUrl?: string }).webhookUrl;
        if (!webhookUrl) throw new Error('Teams channel requires a webhookUrl.');

        // Teams Incoming Webhooks are hosted under *.webhook.office.com /
        // outlook.office.com. The SSRF guard will block private-range
        // targets but allows public HTTPS; no explicit allowedHosts
        // needed since the operator picks the URL from their tenant.
        const title = (config as { title?: string }).title ?? 'Uptime Sentinel';
        const body = {
            '@type': 'MessageCard',
            '@context': 'https://schema.org/extensions',
            themeColor: 'f59e0b',
            summary: title,
            title,
            text: message,
        };

        const response = await safeOutboundFetch(webhookUrl, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(body),
        });

        if (!response.ok) {
            const text = await response.text().catch(() => '<unreadable>');
            // AUDIT-2 #9 (2026-05-24): redact high-entropy substrings.
            throw new Error(`Teams ${response.status}: ${redactHighEntropy(text).slice(0, 256)}`);
        }
    }
}
