import * as React from "react";
import { promises as fs } from "fs";
import { sendEmail } from "@open-mercato/shared/lib/email/send";
import { resolveDefaultEmailFromAddress } from "@open-mercato/shared/lib/email/config";
import { loadDictionary } from "@open-mercato/shared/lib/i18n/server";
import { defaultLocale } from "@open-mercato/shared/lib/i18n/config";
import { createFallbackTranslator } from "@open-mercato/shared/lib/i18n/translate";
import { MessageAccessToken } from "../data/entities.js";
import MessageEmail from "../emails/MessageEmail.js";
import { resolveAttachmentAbsolutePath } from "../../attachments/lib/storage.js";
import { generateAuthToken, hashAuthToken } from "../../auth/lib/tokenHash.js";
import { createLogger } from "@open-mercato/shared/lib/logger";
const logger = createLogger("messages").child({ component: "email-sender" });
const ACCESS_TOKEN_EXPIRY_HOURS = 24 * 7;
const MAX_EMAIL_ATTACHMENTS = 10;
const MAX_TOTAL_ATTACHMENT_BYTES = 20 * 1024 * 1024;
function logDebug(message, details) {
  logger.debug(message, details);
}
function resolveAppUrl() {
  const raw = process.env.APP_URL?.trim();
  if (!raw) return null;
  return raw.replace(/\/$/, "");
}
function buildSenderLabel(sender) {
  const name = sender.name?.trim();
  if (name) return name;
  const email = sender.email?.trim();
  if (email) return email;
  return "System";
}
function resolveObjectLabels(objects) {
  return objects.map((item) => `${item.entityModule}.${item.entityType} (${item.entityId})`);
}
async function mapAttachmentsForEmail(messageId, attachments) {
  const resendAttachments = [];
  let totalBytes = 0;
  for (const attachment of attachments.slice(0, MAX_EMAIL_ATTACHMENTS)) {
    const absolutePath = resolveAttachmentAbsolutePath(
      attachment.partitionCode,
      attachment.storagePath,
      attachment.storageDriver
    );
    let buffer;
    try {
      buffer = await fs.readFile(absolutePath);
    } catch (error) {
      logDebug("Attachment skipped: file read failed", {
        messageId,
        fileName: attachment.fileName,
        error: error instanceof Error ? error.message : String(error)
      });
      continue;
    }
    if (totalBytes + buffer.length > MAX_TOTAL_ATTACHMENT_BYTES) {
      logDebug("Attachment skipped: total size limit exceeded", {
        messageId,
        fileName: attachment.fileName,
        nextTotalBytes: totalBytes + buffer.length
      });
      continue;
    }
    totalBytes += buffer.length;
    resendAttachments.push({
      filename: attachment.fileName,
      content: buffer.toString("base64"),
      contentType: attachment.mimeType || void 0
    });
  }
  return resendAttachments;
}
async function renderMarkdownEmailBody(body) {
  const ReactMarkdownModule = await import("react-markdown");
  const remarkGfmModule = await import("remark-gfm");
  const ReactMarkdown = ReactMarkdownModule.default ?? ReactMarkdownModule;
  const remarkGfmPlugin = remarkGfmModule.default ?? remarkGfmModule;
  const { renderToStaticMarkup } = await import("react-dom/server");
  return renderToStaticMarkup(
    React.createElement(ReactMarkdown, { remarkPlugins: [remarkGfmPlugin] }, body)
  );
}
async function buildEmailBodyHtml(message) {
  if (message.bodyFormat !== "markdown") return void 0;
  if (!message.body) return void 0;
  return renderMarkdownEmailBody(message.body);
}
async function buildEmailCopy(sentAt) {
  const dict = await loadDictionary(defaultLocale);
  const t = createFallbackTranslator(dict);
  return {
    preview: t("messages.email.preview", "You received a message in Open Mercato"),
    heading: t("messages.email.heading", "New message"),
    from: t("messages.email.from", "From"),
    sentAt: t("messages.email.sentAt", "Sent"),
    sentAtLabel: sentAt.toISOString(),
    viewCta: t("messages.email.viewCta", "View message"),
    attachmentsLabel: t("messages.email.attachments", "Attachments"),
    objectsLabel: t("messages.email.objects", "Related records"),
    footer: t("messages.email.footer", "Open Mercato messages")
  };
}
async function createMessageAccessToken(em, messageId, recipientUserId) {
  const rawToken = generateAuthToken();
  const expiresAt = new Date(Date.now() + ACCESS_TOKEN_EXPIRY_HOURS * 60 * 60 * 1e3);
  const record = em.create(MessageAccessToken, {
    messageId,
    recipientUserId,
    token: hashAuthToken(rawToken),
    expiresAt,
    useCount: 0
  });
  await em.persist(record).flush();
  logDebug("Created access token", {
    messageId,
    recipientUserId,
    expiresAt: expiresAt.toISOString()
  });
  return rawToken;
}
async function sendMessageEmailToRecipient(params) {
  const { em, message, recipientUserId, recipientEmail, sender, objects, attachments } = params;
  const token = await createMessageAccessToken(em, message.id, recipientUserId);
  const appUrl = resolveAppUrl();
  const viewUrl = appUrl ? `${appUrl}/messages/view/${token}` : null;
  if (!appUrl) {
    logDebug("APP_URL missing - email link omitted", { messageId: message.id });
  }
  const copy = await buildEmailCopy(message.sentAt ?? /* @__PURE__ */ new Date());
  const bodyHtml = await buildEmailBodyHtml(message);
  const resendAttachments = await mapAttachmentsForEmail(message.id, attachments);
  logDebug("Sending recipient email via Resend", {
    messageId: message.id,
    recipientUserId,
    recipientEmail,
    hasViewUrl: Boolean(viewUrl),
    attachmentsCount: resendAttachments.length,
    hasApiKey: Boolean(process.env.RESEND_API_KEY),
    from: resolveDefaultEmailFromAddress() ?? null
  });
  await sendEmail({
    to: recipientEmail,
    subject: message.subject,
    react: MessageEmail({
      subject: message.subject,
      body: message.body,
      bodyHtml,
      senderName: buildSenderLabel(sender),
      sentAtLabel: copy.sentAtLabel,
      viewUrl,
      copy,
      attachmentNames: attachments.map((item) => item.fileName),
      objectLabels: resolveObjectLabels(objects)
    }),
    attachments: resendAttachments
  });
}
async function sendMessageEmailToExternal(params) {
  const { message, email, sender, objects, attachments } = params;
  const copy = await buildEmailCopy(message.sentAt ?? /* @__PURE__ */ new Date());
  const bodyHtml = await buildEmailBodyHtml(message);
  const resendAttachments = await mapAttachmentsForEmail(message.id, attachments);
  logDebug("Sending external email via Resend", {
    messageId: message.id,
    email,
    attachmentsCount: resendAttachments.length,
    hasApiKey: Boolean(process.env.RESEND_API_KEY),
    from: resolveDefaultEmailFromAddress() ?? null
  });
  await sendEmail({
    to: email,
    subject: message.subject,
    react: MessageEmail({
      subject: message.subject,
      body: message.body,
      bodyHtml,
      senderName: buildSenderLabel(sender),
      sentAtLabel: copy.sentAtLabel,
      viewUrl: null,
      copy,
      attachmentNames: attachments.map((item) => item.fileName),
      objectLabels: resolveObjectLabels(objects)
    }),
    attachments: resendAttachments
  });
  logDebug("External email sent via Resend", {
    messageId: message.id,
    email
  });
}
export {
  createMessageAccessToken,
  sendMessageEmailToExternal,
  sendMessageEmailToRecipient
};
//# sourceMappingURL=email-sender.js.map
