"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
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 __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var MailService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MailService = void 0;
const api_locale_1 = require("@hed-hog/api-locale");
const api_mail_1 = require("@hed-hog/api-mail");
const api_prisma_1 = require("@hed-hog/api-prisma");
const common_1 = require("@nestjs/common");
const Handlebars = __importStar(require("handlebars"));
const integration_developer_api_service_1 = require("../integration/services/integration-developer-api.service");
const setting_service_1 = require("../setting/setting.service");
let MailService = MailService_1 = class MailService {
    constructor(prismaService, mailMainService, localeService, setting, integrationApi) {
        this.prismaService = prismaService;
        this.mailMainService = mailMainService;
        this.localeService = localeService;
        this.setting = setting;
        this.integrationApi = integrationApi;
        this.logger = new common_1.Logger(MailService_1.name);
        this.modelName = 'mail';
    }
    onModuleInit() {
        this.integrationApi.subscribe({
            eventName: 'core.setting.changed',
            consumerName: 'core.mail-config-validator',
            priority: 0,
            handler: async (event) => {
                var _a;
                const slug = String(((_a = event.payload) === null || _a === void 0 ? void 0 : _a.slug) || '').trim();
                if (!this.isMailConfigSlug(slug)) {
                    return;
                }
                await this.syncConfiguredMailFlag();
            },
        });
        void this.syncConfiguredMailFlag();
    }
    isMailConfigSlug(slug) {
        return slug === 'mail-profile-id';
    }
    isSettingEnabled(value) {
        return value === true || value === 'true';
    }
    async syncConfiguredMailFlag() {
        try {
            const settings = await this.setting.getSettingValues(['mail-profile-id']);
            const profileId = settings['mail-profile-id'];
            if (!profileId || Number(profileId) <= 0) {
                await this.setting.setValue('configured-mail', 'false');
                return;
            }
            const { from, config } = await this.reloadConfig();
            await this.mailMainService.send({
                to: from,
                from,
                subject: '[HedHog] Mail configuration validation',
                body: `This is an automatic validation email for the configured profile (id: ${profileId}).`,
            });
            await this.setting.setValue('configured-mail', 'true');
        }
        catch (error) {
            this.logger.warn(`Mail configuration validation failed: ${error instanceof Error ? error.message : String(error)}`);
            await this.setting.setValue('configured-mail', 'false');
        }
    }
    /**
     * Reload mail configuration from database and update MailMainService.
     * Returns the active from address and the built config object.
     */
    async reloadConfig() {
        try {
            const settings = await this.setting.getSettingValues(['mail-profile-id']);
            const profileId = Number(settings['mail-profile-id']);
            if (!profileId || profileId <= 0) {
                throw new common_1.BadRequestException('No mail profile configured. Set a mail profile in the Mail settings.');
            }
            const profile = await this.prismaService.mail_profile.findUnique({
                where: { id: profileId },
            });
            if (!profile) {
                throw new common_1.NotFoundException(`Mail profile with id ${profileId} not found.`);
            }
            const config = this.buildMailConfig(profile);
            this.mailMainService.setConfig(config);
            this.logger.log(`Mail configuration reloaded from profile "${profile.name}" (${profile.provider})`);
            const from = profile.from_name
                ? `${profile.from_name} <${profile.from_email}>`
                : profile.from_email;
            return { success: true, provider: profile.provider, from, config };
        }
        catch (error) {
            this.logger.error('Error reloading mail configuration:', error);
            throw error;
        }
    }
    buildMailConfig(profile) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
        switch (profile.provider) {
            case 'GMAIL':
                return {
                    global: true,
                    type: 'GMAIL',
                    clientId: (_a = profile.gmail_client_id) !== null && _a !== void 0 ? _a : '',
                    clientSecret: (_b = profile.gmail_client_secret) !== null && _b !== void 0 ? _b : '',
                    refreshToken: (_c = profile.gmail_refresh_token) !== null && _c !== void 0 ? _c : '',
                    from: profile.from_email,
                };
            case 'SMTP':
                return {
                    global: true,
                    type: 'SMTP',
                    host: (_d = profile.smtp_host) !== null && _d !== void 0 ? _d : '',
                    port: (_e = profile.smtp_port) !== null && _e !== void 0 ? _e : 587,
                    secure: (_f = profile.smtp_secure) !== null && _f !== void 0 ? _f : false,
                    username: (_g = profile.smtp_username) !== null && _g !== void 0 ? _g : '',
                    password: (_h = profile.smtp_password) !== null && _h !== void 0 ? _h : '',
                };
            case 'SES':
                return {
                    global: true,
                    type: 'SES',
                    region: (_j = profile.ses_region) !== null && _j !== void 0 ? _j : '',
                    accessKeyId: (_k = profile.ses_access_key_id) !== null && _k !== void 0 ? _k : '',
                    secretAccessKey: (_l = profile.ses_secret_access_key) !== null && _l !== void 0 ? _l : '',
                    from: profile.from_email,
                };
            default:
                throw new common_1.BadRequestException(`Invalid mail provider: ${profile.provider}`);
        }
    }
    async list(locale, paginationParams) {
        const result = await this.localeService.listModelWithLocale(locale, this.modelName, paginationParams);
        if (result.data && Array.isArray(result.data)) {
            const mailIds = result.data.map((item) => item.mail_id).filter(Boolean);
            const mailVars = await this.prismaService.mail_var.findMany({
                where: {
                    mail_id: {
                        in: mailIds,
                    },
                },
                select: {
                    id: true,
                    mail_id: true,
                    name: true,
                },
            });
            const varsByMailId = mailVars.reduce((acc, mailVar) => {
                if (!acc[mailVar.mail_id]) {
                    acc[mailVar.mail_id] = [];
                }
                acc[mailVar.mail_id].push(mailVar);
                return acc;
            }, {});
            result.data = result.data.map((item) => (Object.assign(Object.assign({}, item), { mail_var: varsByMailId[item.mail_id] || [] })));
        }
        return result;
    }
    async get(locale, id) {
        const localeRecord = await this.localeService.getByCode(locale);
        const mail = await this.prismaService.mail.findUnique({
            where: { id },
            include: {
                mail_locale: {
                    where: { locale_id: localeRecord.id },
                    include: { locale: { select: { code: true } } },
                },
                mail_var: {
                    select: {
                        id: true,
                        name: true,
                    },
                },
            },
        });
        if (!mail) {
            throw new common_1.NotFoundException((0, api_locale_1.getLocaleText)('mail.template.not_found', locale, `Mail template with id ${id} not found`));
        }
        const localeData = mail.mail_locale[0];
        return {
            id: mail.id,
            slug: mail.slug,
            locale_id: localeData === null || localeData === void 0 ? void 0 : localeData.locale_id,
            mail_id: mail.id,
            subject: (localeData === null || localeData === void 0 ? void 0 : localeData.subject) || '',
            body: (localeData === null || localeData === void 0 ? void 0 : localeData.body) || '',
            mail_var: mail.mail_var,
            locale: localeData === null || localeData === void 0 ? void 0 : localeData.locale,
            created_at: mail.created_at,
            updated_at: mail.updated_at,
        };
    }
    async create(data) {
        const { slug, mail_locale, mail_var } = data;
        const existing = await this.prismaService.mail.findUnique({
            where: { slug },
        });
        if (existing) {
            throw new common_1.BadRequestException(`Template with slug "${slug}" already exists.`);
        }
        return this.prismaService.mail.create({
            data: {
                slug,
                mail_locale: mail_locale
                    ? {
                        create: mail_locale.map((ml) => ({
                            locale_id: ml.locale_id,
                            subject: ml.subject,
                            body: ml.body,
                        })),
                    }
                    : undefined,
                mail_var: mail_var
                    ? {
                        create: mail_var.map((mv) => ({
                            name: mv.name,
                        })),
                    }
                    : undefined,
            },
            include: {
                mail_locale: true,
                mail_var: true,
            },
        });
    }
    async update({ id, data }) {
        const { slug, mail_locale, mail_var } = data;
        const existingMail = await this.prismaService.mail.findUnique({
            where: { id },
        });
        if (!existingMail) {
            throw new common_1.BadRequestException(`Template with id ${id} not found.`);
        }
        if (slug && slug !== existingMail.slug) {
            const slugExists = await this.prismaService.mail.findUnique({
                where: { slug },
            });
            if (slugExists) {
                throw new common_1.BadRequestException(`Template with slug "${slug}" already exists.`);
            }
            await this.prismaService.mail.update({
                where: { id },
                data: { slug },
            });
        }
        if (mail_locale && mail_locale.length > 0) {
            for (const ml of mail_locale) {
                const existingLocale = await this.prismaService.mail_locale.findFirst({
                    where: {
                        mail_id: id,
                        locale_id: ml.locale_id,
                    },
                });
                if (existingLocale) {
                    await this.prismaService.mail_locale.update({
                        where: { id: existingLocale.id },
                        data: {
                            subject: ml.subject,
                            body: ml.body,
                        },
                    });
                }
                else {
                    await this.prismaService.mail_locale.create({
                        data: {
                            mail_id: id,
                            locale_id: ml.locale_id,
                            subject: ml.subject,
                            body: ml.body,
                        },
                    });
                }
            }
        }
        if (mail_var !== undefined) {
            await this.prismaService.mail_var.deleteMany({
                where: { mail_id: id },
            });
            if (mail_var.length > 0) {
                await this.prismaService.mail_var.createMany({
                    data: mail_var.map((mv) => ({
                        mail_id: id,
                        name: mv.name,
                    })),
                });
            }
        }
        return this.prismaService.mail.findUnique({
            where: { id },
            include: {
                mail_locale: true,
                mail_var: true,
            },
        });
    }
    async delete({ ids }) {
        if (ids == undefined || ids == null) {
            throw new common_1.BadRequestException('You must select at least one item to delete.');
        }
        return this.prismaService.mail.deleteMany({
            where: {
                id: {
                    in: ids,
                },
            },
        });
    }
    async sendTemplatedMail(locale, { email, slug, variables }) {
        const settings = await this.setting.getSettingValues(['configured-mail']);
        if (!this.isSettingEnabled(settings['configured-mail'])) {
            this.logger.warn('Mail service is not configured. Aborting sending email.');
            return;
        }
        try {
            const { from } = await this.reloadConfig();
            const localeRecord = await this.getLocaleRecord(locale);
            const mail = await this.getMailTemplate(slug, localeRecord.id);
            const { subject, body } = mail.mail_locale[0];
            const parsedSubject = this.interpolateTemplate(subject, variables);
            const parsedBody = this.interpolateTemplate(body, variables);
            await this.mailMainService.send({
                to: email,
                from,
                subject: parsedSubject,
                body: parsedBody,
                mail_id: mail.id,
            });
        }
        catch (error) {
            this.logger.error('Error sending templated mail:', error);
            await this.setting.setValue('configured-mail', 'false');
        }
    }
    async getLocaleRecord(locale) {
        const localeRecord = await this.prismaService.locale.findUnique({
            where: { code: locale },
        });
        if (!localeRecord) {
            throw new Error(`Locale "${locale}" not found`);
        }
        return localeRecord;
    }
    async getMailTemplate(slug, localeId) {
        const mail = await this.prismaService.mail.findUnique({
            where: { slug },
            include: {
                mail_locale: {
                    where: { locale_id: localeId },
                    select: { subject: true, body: true },
                },
                mail_var: {
                    select: { name: true },
                },
            },
        });
        if (!mail) {
            throw new Error(`Template "${slug}" not found for locale "${localeId}"`);
        }
        return mail;
    }
    interpolateTemplate(source, data) {
        try {
            const template = Handlebars.compile(source.replace(/(\r\n|\n|\r)/g, '<br/>'));
            return template(data);
        }
        catch (error) {
            this.logger.error('Handlebars template compilation error:', error);
            throw new common_1.BadRequestException(`Invalid template syntax: ${error.message}. Please use {{variable}} format for variables.`);
        }
    }
    async sendTestMail(locale, { slug, email, subject, body, variables, }) {
        const localeRecord = await this.getLocaleRecord(locale);
        const mail = await this.getMailTemplate(slug, localeRecord.id);
        const settings = await this.setting.getSettingValues(['configured-mail']);
        if (!this.isSettingEnabled(settings['configured-mail'])) {
            throw new common_1.BadRequestException('Mail service is not configured.');
        }
        const { from } = await this.reloadConfig();
        try {
            const parsedSubject = variables
                ? this.interpolateTemplate(subject, variables)
                : subject;
            const parsedBody = variables
                ? this.interpolateTemplate(body, variables)
                : body;
            return this.mailMainService.send({
                to: email,
                subject: parsedSubject,
                body: parsedBody,
                mail_id: mail.id,
                from,
            });
        }
        catch (error) {
            this.logger.error('Error sending test mail:', error);
            throw new common_1.BadRequestException('Failed to send test email');
        }
    }
    async importTemplates({ data, overwrite }) {
        const conflicts = [];
        if (!overwrite) {
            for (const template of data) {
                const existing = await this.prismaService.mail.findUnique({
                    where: { slug: template.slug },
                });
                if (existing) {
                    conflicts.push(template.slug);
                }
            }
            if (conflicts.length > 0) {
                return { conflicts };
            }
        }
        const imported = [];
        for (const template of data) {
            try {
                const locales = await this.prismaService.locale.findMany({
                    where: {
                        code: {
                            in: template.translations.map((t) => t.code),
                        },
                    },
                });
                const localeMap = new Map(locales.map((locale) => [locale.code, locale.id]));
                const existing = await this.prismaService.mail.findUnique({
                    where: { slug: template.slug },
                });
                if (existing && overwrite) {
                    await this.prismaService.mail_locale.deleteMany({
                        where: { mail_id: existing.id },
                    });
                    await this.prismaService.mail_var.deleteMany({
                        where: { mail_id: existing.id },
                    });
                    await this.prismaService.mail_locale.createMany({
                        data: template.translations.map((translation) => ({
                            mail_id: existing.id,
                            locale_id: localeMap.get(translation.code),
                            subject: translation.subject,
                            body: translation.body,
                        })),
                    });
                    if (template.variables && template.variables.length > 0) {
                        await this.prismaService.mail_var.createMany({
                            data: template.variables.map((variable) => ({
                                mail_id: existing.id,
                                name: variable,
                            })),
                        });
                    }
                    imported.push(existing.id);
                }
                else if (!existing) {
                    const newMail = await this.prismaService.mail.create({
                        data: {
                            slug: template.slug,
                            mail_locale: {
                                create: template.translations.map((translation) => ({
                                    locale_id: localeMap.get(translation.code),
                                    subject: translation.subject,
                                    body: translation.body,
                                })),
                            },
                            mail_var: template.variables
                                ? {
                                    create: template.variables.map((variable) => ({
                                        name: variable,
                                    })),
                                }
                                : undefined,
                        },
                    });
                    imported.push(newMail.id);
                }
            }
            catch (error) {
                this.logger.error(`Error importing template ${template.slug}:`, error);
                const message = error instanceof Error ? error.message : 'Unknown error';
                throw new common_1.BadRequestException(`Failed to import template "${template.slug}": ${message}`);
            }
        }
        return {
            success: true,
            imported: imported.length,
            templates: imported,
        };
    }
};
exports.MailService = MailService;
exports.MailService = MailService = MailService_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, common_1.Inject)((0, common_1.forwardRef)(() => api_prisma_1.PrismaService))),
    __param(1, (0, common_1.Inject)((0, common_1.forwardRef)(() => api_mail_1.MailService))),
    __param(2, (0, common_1.Inject)((0, common_1.forwardRef)(() => api_locale_1.LocaleService))),
    __param(3, (0, common_1.Inject)((0, common_1.forwardRef)(() => setting_service_1.SettingService))),
    __param(4, (0, common_1.Inject)((0, common_1.forwardRef)(() => integration_developer_api_service_1.IntegrationDeveloperApiService))),
    __metadata("design:paramtypes", [api_prisma_1.PrismaService,
        api_mail_1.MailService,
        api_locale_1.LocaleService,
        setting_service_1.SettingService,
        integration_developer_api_service_1.IntegrationDeveloperApiService])
], MailService);
//# sourceMappingURL=mail.service.js.map