"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebhookIntegrationService = void 0;
const api_mail_1 = require("@hed-hog/api-mail");
const api_pagination_1 = require("@hed-hog/api-pagination");
const api_prisma_1 = require("@hed-hog/api-prisma");
const axios_1 = require("@nestjs/axios");
const common_1 = require("@nestjs/common");
const events_1 = require("events");
const rxjs_1 = require("rxjs");
const mail_service_1 = require("../mail/mail.service");
const setting_service_1 = require("../setting/setting.service");
const webhook_utils_1 = require("./webhook-utils");
let WebhookIntegrationService = class WebhookIntegrationService {
    constructor(prisma, pagination, http, mailMainService, coreMailService, settingService) {
        this.prisma = prisma;
        this.pagination = pagination;
        this.http = http;
        this.mailMainService = mailMainService;
        this.coreMailService = coreMailService;
        this.settingService = settingService;
        this.logEmitter = new events_1.EventEmitter();
    }
    get integrations() {
        return this.prisma.webhook_integration;
    }
    get actions() {
        return this.prisma.webhook_action;
    }
    get logs() {
        return this.prisma.webhook_call_log;
    }
    get actionLogs() {
        return this.prisma.webhook_action_log;
    }
    async list(paginationParams) {
        const fields = ['slug', 'name', 'description', 'public_uuid', 'status'];
        const OR = this.prisma.createInsensitiveSearch(fields, paginationParams);
        const result = await this.pagination.paginate(this.integrations, paginationParams, {
            where: OR.length > 0 ? { OR } : {},
            include: {
                webhook_action: {
                    orderBy: [{ order: 'asc' }, { id: 'asc' }],
                },
            },
            orderBy: [{ updated_at: 'desc' }, { id: 'desc' }],
        });
        return Object.assign(Object.assign({}, result), { data: await this.withPublicUrls(result.data || []) });
    }
    async get(id) {
        const record = await this.integrations.findUnique({
            where: { id },
            include: {
                webhook_action: {
                    orderBy: [{ order: 'asc' }, { id: 'asc' }],
                },
            },
        });
        if (!record) {
            throw new common_1.NotFoundException(`Webhook integration with id ${id} not found.`);
        }
        return this.withPublicUrl(record);
    }
    async create(data) {
        await this.ensureSlugAvailable(data.slug);
        let plainToken = null;
        if (data.require_token) {
            plainToken = (0, webhook_utils_1.createPlainToken)();
        }
        const record = await this.integrations.create({
            data: Object.assign(Object.assign({}, this.normalizeIntegration(data)), { public_uuid: (0, webhook_utils_1.createPublicUuid)(), token_hash: plainToken ? (0, webhook_utils_1.hashToken)(plainToken) : null }),
        });
        return Object.assign(Object.assign({}, (await this.withPublicUrl(record))), { plainToken });
    }
    async update(id, data) {
        const existing = await this.get(id);
        if (data.slug && data.slug !== existing.slug) {
            await this.ensureSlugAvailable(data.slug);
        }
        let plainToken = null;
        const updateData = this.normalizeIntegration(data, true);
        if (data.require_token === false) {
            updateData.token_hash = null;
        }
        else if (data.require_token === true && !existing.token_hash) {
            plainToken = (0, webhook_utils_1.createPlainToken)();
            updateData.token_hash = (0, webhook_utils_1.hashToken)(plainToken);
        }
        const record = await this.integrations.update({
            where: { id },
            data: updateData,
        });
        return Object.assign(Object.assign({}, (await this.withPublicUrl(record))), { plainToken });
    }
    async delete(data) {
        var _a;
        if (!((_a = data.ids) === null || _a === void 0 ? void 0 : _a.length)) {
            throw new common_1.BadRequestException('You must select at least one item to delete.');
        }
        return this.integrations.deleteMany({
            where: { id: { in: data.ids } },
        });
    }
    async regenerateUuid(id) {
        await this.get(id);
        const record = await this.integrations.update({
            where: { id },
            data: { public_uuid: (0, webhook_utils_1.createPublicUuid)() },
        });
        return this.withPublicUrl(record);
    }
    async regenerateToken(id) {
        await this.get(id);
        const plainToken = (0, webhook_utils_1.createPlainToken)();
        const record = await this.integrations.update({
            where: { id },
            data: {
                require_token: true,
                token_hash: (0, webhook_utils_1.hashToken)(plainToken),
            },
        });
        return Object.assign(Object.assign({}, (await this.withPublicUrl(record))), { plainToken });
    }
    async getApplicationBaseUrl() {
        const settings = await this.settingService.getSettingValues([
            'api-url',
            'url',
        ]);
        const value = (settings === null || settings === void 0 ? void 0 : settings['api-url']) || (settings === null || settings === void 0 ? void 0 : settings.url);
        return typeof value === 'string' ? value.replace(/\/+$/, '') : '';
    }
    async withPublicUrl(record) {
        const baseUrl = await this.getApplicationBaseUrl();
        return Object.assign(Object.assign({}, record), { public_url: baseUrl && record.public_uuid
                ? `${baseUrl}/webhook/${record.public_uuid}`
                : null });
    }
    async withPublicUrls(records) {
        const baseUrl = await this.getApplicationBaseUrl();
        return records.map((record) => (Object.assign(Object.assign({}, record), { public_url: baseUrl && record.public_uuid
                ? `${baseUrl}/webhook/${record.public_uuid}`
                : null })));
    }
    async listActions(integrationId) {
        await this.get(integrationId);
        return this.actions.findMany({
            where: { webhook_integration_id: integrationId },
            orderBy: [{ order: 'asc' }, { id: 'asc' }],
        });
    }
    async createAction(integrationId, data) {
        await this.get(integrationId);
        const normalized = this.normalizeAction(data);
        this.validateActionConfiguration(normalized);
        return this.actions.create({
            data: Object.assign(Object.assign({}, normalized), { webhook_integration_id: integrationId }),
        });
    }
    async updateAction(integrationId, actionId, data) {
        const existing = await this.ensureAction(integrationId, actionId);
        const normalized = this.normalizeAction(data, true);
        this.validateActionConfiguration(Object.assign(Object.assign({}, existing), normalized));
        return this.actions.update({
            where: { id: actionId },
            data: normalized,
        });
    }
    async deleteActions(integrationId, data) {
        var _a;
        await this.get(integrationId);
        if (!((_a = data.ids) === null || _a === void 0 ? void 0 : _a.length)) {
            throw new common_1.BadRequestException('You must select at least one item to delete.');
        }
        return this.actions.deleteMany({
            where: {
                webhook_integration_id: integrationId,
                id: { in: data.ids },
            },
        });
    }
    async listLogs(integrationId, paginationParams, sort = 'desc') {
        await this.get(integrationId);
        const page = Math.max(Number(paginationParams.page || 1), 1);
        const pageSize = Math.max(Number(paginationParams.pageSize || 10), 1);
        const skip = (page - 1) * pageSize;
        const normalizedSort = sort === 'asc' ? 'asc' : 'desc';
        const where = { webhook_integration_id: integrationId };
        const [data, total] = await Promise.all([
            this.logs.findMany({
                where,
                orderBy: [{ created_at: normalizedSort }, { id: normalizedSort }],
                skip,
                take: pageSize,
            }),
            this.logs.count({ where }),
        ]);
        const lastPage = Math.max(1, Math.ceil(total / pageSize));
        const result = {
            total,
            lastPage,
            page,
            pageSize,
            prev: page > 1 ? page - 1 : null,
            next: page < lastPage ? page + 1 : null,
            data,
        };
        const logIds = (result.data || [])
            .map((item) => item.id)
            .filter((id) => typeof id === 'number');
        if (!logIds.length || !this.actionLogs) {
            return result;
        }
        const actionLogs = await this.actionLogs.findMany({
            where: {
                webhook_call_log_id: { in: logIds },
            },
            orderBy: [{ created_at: 'asc' }, { id: 'asc' }],
        });
        const actionLogsByCallId = new Map();
        for (const actionLog of actionLogs || []) {
            const list = actionLogsByCallId.get(actionLog.webhook_call_log_id) || [];
            list.push(actionLog);
            actionLogsByCallId.set(actionLog.webhook_call_log_id, list);
        }
        return Object.assign(Object.assign({}, result), { data: (result.data || []).map((item) => (Object.assign(Object.assign({}, item), { webhook_action_log: actionLogsByCallId.get(item.id) || [] }))) });
    }
    streamLogs(integrationId, res) {
        res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
        res.setHeader('Cache-Control', 'no-cache, no-transform');
        res.setHeader('Connection', 'keep-alive');
        res.setHeader('X-Accel-Buffering', 'no');
        res.flushHeaders();
        res.write(`data: ${JSON.stringify({ type: 'connected' })}\n\n`);
        const handler = (payload) => {
            res.write(`data: ${JSON.stringify({ type: 'log', payload })}\n\n`);
        };
        const eventKey = `log:${integrationId}`;
        this.logEmitter.on(eventKey, handler);
        res.on('close', () => {
            this.logEmitter.off(eventKey, handler);
        });
    }
    async executePublic(uuid, body, headers, req) {
        const startedAt = Date.now();
        const remoteIp = this.getRemoteIp(req);
        const actionLogs = [];
        let integration = null;
        try {
            integration = await this.integrations.findUnique({
                where: { public_uuid: uuid },
                include: {
                    webhook_action: {
                        where: { status: 'active' },
                        orderBy: [{ order: 'asc' }, { id: 'asc' }],
                    },
                },
            });
            if (!integration || integration.status !== 'active') {
                throw new common_1.NotFoundException('Webhook not found.');
            }
            this.validateToken(integration, headers);
            this.validateIp(integration, remoteIp);
            this.validateBodySchema(integration, body);
            const actionResults = [];
            for (const action of integration.webhook_action || []) {
                const actionStartedAt = Date.now();
                try {
                    const result = await this.executeAction(action, body);
                    const durationMs = Date.now() - actionStartedAt;
                    actionResults.push({
                        id: action.id,
                        type: action.type,
                        success: true,
                        duration_ms: durationMs,
                        response: (0, webhook_utils_1.summarizePayload)(result.responsePayload),
                    });
                    actionLogs.push({
                        webhookActionId: action.id,
                        actionName: action.name,
                        actionType: action.type,
                        status: 'success',
                        durationMs,
                        requestPayload: result.requestPayload,
                        responsePayload: result.responsePayload,
                    });
                }
                catch (error) {
                    const durationMs = Date.now() - actionStartedAt;
                    const errorMessage = this.extractErrorMessage(error);
                    actionResults.push({
                        id: action.id,
                        type: action.type,
                        success: false,
                        duration_ms: durationMs,
                        error: errorMessage,
                        response: (0, webhook_utils_1.summarizePayload)(this.extractErrorResponse(error)),
                    });
                    actionLogs.push({
                        webhookActionId: action.id,
                        actionName: action.name,
                        actionType: action.type,
                        status: 'failed',
                        durationMs,
                        requestPayload: this.extractErrorRequestPayload(error),
                        errorMessage,
                        responsePayload: this.extractErrorResponse(error),
                    });
                    throw error;
                }
            }
            const response = {
                success: true,
                actions: actionResults,
            };
            const callLog = await this.createCallLog({
                integration,
                uuid,
                status: 'success',
                remoteIp,
                durationMs: Date.now() - startedAt,
                payload: body,
                response,
            });
            await this.createActionLogs(callLog === null || callLog === void 0 ? void 0 : callLog.id, actionLogs);
            if ((integration === null || integration === void 0 ? void 0 : integration.id) && (callLog === null || callLog === void 0 ? void 0 : callLog.id)) {
                this.logEmitter.emit(`log:${integration.id}`, { id: callLog.id });
            }
            return response;
        }
        catch (error) {
            const callLog = await this.createCallLog({
                integration,
                uuid,
                status: 'failed',
                remoteIp,
                durationMs: Date.now() - startedAt,
                payload: body,
                response: {
                    success: false,
                    actions: actionLogs.map((item) => ({
                        id: item.webhookActionId,
                        type: item.actionType,
                        success: item.status === 'success',
                        duration_ms: item.durationMs,
                        error: item.errorMessage || null,
                    })),
                },
                error,
            }).catch(() => null);
            await this.createActionLogs(callLog === null || callLog === void 0 ? void 0 : callLog.id, actionLogs).catch(() => undefined);
            if ((integration === null || integration === void 0 ? void 0 : integration.id) && (callLog === null || callLog === void 0 ? void 0 : callLog.id)) {
                this.logEmitter.emit(`log:${integration.id}`, { id: callLog.id });
            }
            if (error instanceof common_1.HttpException) {
                throw error;
            }
            return {
                success: false,
                actions: actionLogs.map((item) => ({
                    id: item.webhookActionId,
                    type: item.actionType,
                    success: item.status === 'success',
                    duration_ms: item.durationMs,
                    error: item.errorMessage || null,
                })),
            };
        }
    }
    async executeAction(action, body) {
        if (action.type === 'email') {
            return this.executeEmailAction(action, body);
        }
        if (action.type === 'whatsapp_evolution') {
            return this.executeWhatsappAction(action, body);
        }
        throw new common_1.BadRequestException(`Unsupported action type: ${action.type}`);
    }
    async executeEmailAction(action, body) {
        var _a, _b, _c, _d;
        this.validateActionConfiguration(action);
        const profile = await this.prisma.mail_profile.findUnique({
            where: { id: Number(action.mail_profile_id) },
        });
        const mail = await this.prisma.mail.findUnique({
            where: { id: Number(action.mail_id) },
            include: {
                mail_locale: {
                    orderBy: [{ locale_id: 'asc' }],
                },
            },
        });
        if (!profile || !((_a = mail === null || mail === void 0 ? void 0 : mail.mail_locale) === null || _a === void 0 ? void 0 : _a.length)) {
            throw new common_1.BadRequestException('Email action references an invalid profile or template.');
        }
        const template = mail.mail_locale[0];
        const config = this.buildMailConfig(profile);
        const sender = profile.from_name
            ? `${profile.from_name} <${profile.from_email}>`
            : profile.from_email;
        const replyTo = profile.reply_to_email
            ? profile.reply_to_name
                ? `${profile.reply_to_name} <${profile.reply_to_email}>`
                : profile.reply_to_email
            : undefined;
        const renderedTo = String((_b = (0, webhook_utils_1.renderTemplate)(action.email_to, body)) !== null && _b !== void 0 ? _b : '').trim();
        const renderedCc = action.email_cc
            ? String((_c = (0, webhook_utils_1.renderTemplate)(action.email_cc, body)) !== null && _c !== void 0 ? _c : '').trim()
            : '';
        const renderedBcc = action.email_bcc
            ? String((_d = (0, webhook_utils_1.renderTemplate)(action.email_bcc, body)) !== null && _d !== void 0 ? _d : '').trim()
            : '';
        if (!renderedTo) {
            throw new common_1.BadRequestException('Email action rendered an empty recipient for email_to.');
        }
        const requestPayload = {
            to: renderedTo,
            cc: renderedCc || undefined,
            bcc: renderedBcc || undefined,
            from: sender,
            replyTo,
            subject: (0, webhook_utils_1.renderTemplate)(template.subject, body),
            body: (0, webhook_utils_1.renderTemplate)(template.body, body),
            mail_id: mail.id,
        };
        try {
            this.mailMainService.setConfig(config);
            const providerResponse = await this.mailMainService.send(requestPayload);
            return {
                requestPayload,
                responsePayload: {
                    provider: 'email',
                    response: providerResponse || null,
                },
            };
        }
        finally {
            await this.coreMailService.reloadConfig().catch(() => undefined);
        }
    }
    async executeWhatsappAction(action, body) {
        var _a, _b;
        const required = [
            action.whatsapp_target,
            action.whatsapp_template,
            action.whatsapp_instance,
            action.whatsapp_base_url,
            action.whatsapp_token,
        ];
        if (required.some((value) => !String(value || '').trim())) {
            throw new common_1.BadRequestException('WhatsApp action is missing required configuration.');
        }
        const baseUrl = String(action.whatsapp_base_url).replace(/\/+$/, '');
        const instance = encodeURIComponent(action.whatsapp_instance);
        const url = `${baseUrl}/message/sendText/${instance}`;
        const targetType = action.whatsapp_target_type === 'group' ? 'group' : 'phone';
        const renderedMessage = String((_a = (0, webhook_utils_1.renderTemplate)(action.whatsapp_template, body)) !== null && _a !== void 0 ? _a : '').trim();
        const renderedTarget = String((_b = (0, webhook_utils_1.renderTemplate)(action.whatsapp_target, body)) !== null && _b !== void 0 ? _b : '').trim();
        if (!renderedMessage) {
            throw new common_1.BadRequestException('WhatsApp action template rendered an empty message.');
        }
        const target = this.normalizeWhatsappTarget(renderedTarget, targetType);
        const requestPayload = {
            provider: 'evolution',
            url,
            instance: action.whatsapp_instance,
            targetType,
            number: target,
            text: renderedMessage,
        };
        let response;
        try {
            response = await (0, rxjs_1.firstValueFrom)(this.http.post(url, {
                number: target,
                text: renderedMessage,
            }, {
                headers: {
                    apikey: action.whatsapp_token,
                },
                timeout: 15000,
            }));
        }
        catch (error) {
            this.attachErrorRequestPayload(error, requestPayload);
            throw error;
        }
        return {
            requestPayload,
            responsePayload: {
                status: (response === null || response === void 0 ? void 0 : response.status) || null,
                statusText: (response === null || response === void 0 ? void 0 : response.statusText) || null,
                data: (response === null || response === void 0 ? void 0 : response.data) || null,
            },
        };
    }
    validateToken(integration, headers) {
        var _a;
        if (!integration.require_token) {
            return;
        }
        const provided = headers['x-webhook-token'] ||
            headers['X-Webhook-Token'] ||
            ((_a = headers.authorization) === null || _a === void 0 ? void 0 : _a.replace(/^Bearer\s+/i, ''));
        if (!provided || (0, webhook_utils_1.hashToken)(String(provided)) !== integration.token_hash) {
            throw new common_1.BadRequestException('Invalid webhook token.');
        }
    }
    validateIp(integration, remoteIp) {
        const allowedIps = Array.isArray(integration.allowed_ips)
            ? integration.allowed_ips
            : [];
        if (!allowedIps.length) {
            return;
        }
        if (!remoteIp || !allowedIps.includes(remoteIp)) {
            throw new common_1.BadRequestException('Remote IP is not allowed.');
        }
    }
    validateActionConfiguration(action) {
        if ((action === null || action === void 0 ? void 0 : action.type) === 'email') {
            const missing = [];
            if (!this.nullableNumber(action.mail_profile_id)) {
                missing.push('mail_profile_id');
            }
            if (!this.nullableNumber(action.mail_id)) {
                missing.push('mail_id');
            }
            if (!this.nullableString(action.email_to, true)) {
                missing.push('email_to');
            }
            if (missing.length) {
                throw new common_1.BadRequestException(`Email action is missing required configuration: ${missing.join(', ')}.`);
            }
        }
        if ((action === null || action === void 0 ? void 0 : action.type) === 'whatsapp_evolution') {
            const missing = [
                ['whatsapp_target', action.whatsapp_target],
                ['whatsapp_template', action.whatsapp_template],
                ['whatsapp_instance', action.whatsapp_instance],
                ['whatsapp_base_url', action.whatsapp_base_url],
                ['whatsapp_token', action.whatsapp_token],
            ]
                .filter(([, value]) => !String(value || '').trim())
                .map(([key]) => key);
            if (missing.length) {
                throw new common_1.BadRequestException(`WhatsApp action is missing required configuration: ${missing.join(', ')}.`);
            }
        }
    }
    validateBodySchema(integration, body) {
        if (!integration.body_schema) {
            return;
        }
        const errors = this.validateJsonSchema(integration.body_schema, body);
        if (errors.length) {
            throw new common_1.BadRequestException({
                message: 'Webhook body does not match the configured schema.',
                errors,
            });
        }
    }
    validateJsonSchema(schema, value, path = '$') {
        if (!schema || typeof schema !== 'object') {
            return [];
        }
        const errors = [];
        const type = schema.type;
        if (type && !this.matchesJsonSchemaType(type, value)) {
            errors.push(`${path} must be ${type}`);
            return errors;
        }
        if (type === 'object' || schema.properties || schema.required) {
            if (!value || typeof value !== 'object' || Array.isArray(value)) {
                errors.push(`${path} must be object`);
                return errors;
            }
            for (const requiredKey of schema.required || []) {
                if (value[requiredKey] === undefined || value[requiredKey] === null) {
                    errors.push(`${path}.${requiredKey} is required`);
                }
            }
            for (const [key, childSchema] of Object.entries(schema.properties || {})) {
                if (value[key] !== undefined) {
                    errors.push(...this.validateJsonSchema(childSchema, value[key], `${path}.${key}`));
                }
            }
        }
        if (type === 'array' && schema.items && Array.isArray(value)) {
            value.forEach((item, index) => {
                errors.push(...this.validateJsonSchema(schema.items, item, `${path}[${index}]`));
            });
        }
        return errors;
    }
    matchesJsonSchemaType(type, value) {
        const types = Array.isArray(type) ? type : [type];
        return types.some((item) => {
            switch (item) {
                case 'object':
                    return (value !== null && typeof value === 'object' && !Array.isArray(value));
                case 'array':
                    return Array.isArray(value);
                case 'string':
                    return typeof value === 'string';
                case 'number':
                    return typeof value === 'number';
                case 'integer':
                    return Number.isInteger(value);
                case 'boolean':
                    return typeof value === 'boolean';
                case 'null':
                    return value === null;
                default:
                    return true;
            }
        });
    }
    async createCallLog(input) {
        var _a, _b;
        if (!this.logs) {
            return null;
        }
        return this.logs.create({
            data: {
                webhook_integration_id: (_b = (_a = input.integration) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : null,
                public_uuid: input.uuid,
                status: input.status,
                remote_ip: input.remoteIp,
                duration_ms: input.durationMs,
                error_message: input.error ? this.extractErrorMessage(input.error) : null,
                payload_summary: (0, webhook_utils_1.summarizePayload)((0, webhook_utils_1.sanitizeSensitiveData)(input.payload)),
                response_summary: (0, webhook_utils_1.summarizePayload)((0, webhook_utils_1.sanitizeSensitiveData)(input.response)),
            },
            select: {
                id: true,
            },
        });
    }
    async createActionLogs(callLogId, logs) {
        if (!callLogId || !logs.length || !this.actionLogs) {
            return;
        }
        await this.actionLogs.createMany({
            data: logs.map((item) => ({
                webhook_call_log_id: callLogId,
                webhook_action_id: item.webhookActionId,
                action_name: item.actionName,
                action_type: item.actionType,
                status: item.status,
                duration_ms: item.durationMs,
                request_payload: (0, webhook_utils_1.summarizePayload)((0, webhook_utils_1.sanitizeSensitiveData)(item.requestPayload)),
                response_payload: (0, webhook_utils_1.summarizePayload)((0, webhook_utils_1.sanitizeSensitiveData)(item.responsePayload)),
                error_message: item.errorMessage || null,
            })),
        });
    }
    extractErrorMessage(error) {
        if (!error) {
            return 'Unknown error';
        }
        if (error instanceof Error && error.message) {
            return error.message;
        }
        if (typeof error === 'object' && error.message) {
            return String(error.message);
        }
        return String(error);
    }
    extractErrorResponse(error) {
        if (!error || typeof error !== 'object') {
            return null;
        }
        const maybeResponse = error.response;
        if (!maybeResponse) {
            return null;
        }
        return {
            status: maybeResponse.status || null,
            statusText: maybeResponse.statusText || null,
            data: maybeResponse.data || null,
        };
    }
    extractErrorRequestPayload(error) {
        if (!error || typeof error !== 'object') {
            return null;
        }
        const maybePayload = error.__webhookRequestPayload;
        return maybePayload || null;
    }
    attachErrorRequestPayload(error, requestPayload) {
        if (!error || typeof error !== 'object') {
            return;
        }
        error.__webhookRequestPayload = requestPayload;
    }
    normalizeWhatsappTarget(renderedTarget, targetType) {
        const rawTarget = String(renderedTarget || '').trim();
        if (!rawTarget) {
            throw new common_1.BadRequestException('WhatsApp action target template rendered an empty value.');
        }
        if (targetType === 'group') {
            return rawTarget;
        }
        const normalized = rawTarget.replace(/\D+/g, '');
        if (!normalized) {
            throw new common_1.BadRequestException('WhatsApp action target must contain at least one digit for phone targets.');
        }
        return normalized;
    }
    getRemoteIp(req) {
        const forwardedFor = req.headers['x-forwarded-for'];
        const forwardedIp = Array.isArray(forwardedFor)
            ? forwardedFor[0]
            : forwardedFor === null || forwardedFor === void 0 ? void 0 : forwardedFor.split(',')[0];
        return (forwardedIp === null || forwardedIp === void 0 ? void 0 : forwardedIp.trim()) || req.ip || req.socket.remoteAddress || null;
    }
    async ensureAction(integrationId, actionId) {
        const record = await this.actions.findFirst({
            where: {
                id: actionId,
                webhook_integration_id: integrationId,
            },
        });
        if (!record) {
            throw new common_1.NotFoundException(`Webhook action with id ${actionId} not found.`);
        }
        return record;
    }
    async ensureSlugAvailable(slug) {
        const existing = await this.integrations.findUnique({
            where: { slug: String(slug || '').trim() },
            select: { id: true },
        });
        if (existing) {
            throw new common_1.BadRequestException(`Webhook integration "${slug}" already exists.`);
        }
    }
    normalizeIntegration(data, partial = false) {
        var _a, _b;
        const normalized = {};
        const assign = (key, value) => {
            if (!partial || value !== undefined) {
                normalized[key] = value;
            }
        };
        assign('slug', String((_a = data.slug) !== null && _a !== void 0 ? _a : '').trim());
        assign('name', String((_b = data.name) !== null && _b !== void 0 ? _b : '').trim());
        assign('description', this.nullableString(data.description, partial));
        assign('status', data.status === 'inactive' ? 'inactive' : 'active');
        assign('require_token', Boolean(data.require_token));
        assign('allowed_ips', (0, webhook_utils_1.normalizeJsonObject)(data.allowed_ips));
        assign('body_schema', (0, webhook_utils_1.normalizeJsonObject)(data.body_schema));
        return normalized;
    }
    normalizeAction(data, partial = false) {
        var _a, _b;
        const normalized = {};
        const assign = (key, value) => {
            if (!partial || value !== undefined) {
                normalized[key] = value;
            }
        };
        assign('type', data.type);
        assign('name', String((_a = data.name) !== null && _a !== void 0 ? _a : '').trim());
        assign('order', Number((_b = data.order) !== null && _b !== void 0 ? _b : 0));
        assign('status', data.status === 'inactive' ? 'inactive' : 'active');
        assign('mail_profile_id', this.nullableNumber(data.mail_profile_id, partial));
        assign('mail_id', this.nullableNumber(data.mail_id, partial));
        assign('email_to', this.nullableString(data.email_to, partial));
        assign('email_cc', this.nullableString(data.email_cc, partial));
        assign('email_bcc', this.nullableString(data.email_bcc, partial));
        assign('whatsapp_target_type', data.whatsapp_target_type || null);
        assign('whatsapp_target', this.nullableString(data.whatsapp_target, partial));
        assign('whatsapp_template', this.nullableString(data.whatsapp_template, partial));
        assign('whatsapp_instance', this.nullableString(data.whatsapp_instance, partial));
        assign('whatsapp_base_url', this.nullableString(data.whatsapp_base_url, partial));
        assign('whatsapp_token', this.nullableString(data.whatsapp_token, partial));
        return normalized;
    }
    nullableString(value, partial = false) {
        if (value === undefined) {
            return partial ? undefined : null;
        }
        if (value === null) {
            return null;
        }
        const normalized = String(value).trim();
        return normalized || null;
    }
    nullableNumber(value, partial = false) {
        if (value === undefined) {
            return partial ? undefined : null;
        }
        if (value === null || value === '') {
            return null;
        }
        return Number(value);
    }
    buildMailConfig(profile) {
        switch (profile.provider) {
            case 'SMTP':
                return {
                    global: true,
                    type: 'SMTP',
                    host: profile.smtp_host,
                    port: Number(profile.smtp_port || 587),
                    secure: Boolean(profile.smtp_secure),
                    username: profile.smtp_username || '',
                    password: profile.smtp_password || '',
                };
            case 'GMAIL':
                return {
                    global: true,
                    type: 'GMAIL',
                    clientId: profile.gmail_client_id,
                    clientSecret: profile.gmail_client_secret,
                    refreshToken: profile.gmail_refresh_token,
                    from: profile.from_email,
                };
            case 'SES':
                return {
                    global: true,
                    type: 'SES',
                    region: profile.ses_region,
                    accessKeyId: profile.ses_access_key_id,
                    secretAccessKey: profile.ses_secret_access_key,
                    from: profile.from_email,
                };
            default:
                throw new common_1.BadRequestException(`Invalid mail profile provider: ${profile.provider}`);
        }
    }
};
exports.WebhookIntegrationService = WebhookIntegrationService;
exports.WebhookIntegrationService = WebhookIntegrationService = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [api_prisma_1.PrismaService,
        api_pagination_1.PaginationService,
        axios_1.HttpService,
        api_mail_1.MailService,
        mail_service_1.MailService,
        setting_service_1.SettingService])
], WebhookIntegrationService);
//# sourceMappingURL=webhook-integration.service.js.map