import { transport } from "./mailer";
import { getEmailTemplate } from "./payload";
import { renderOrderConfirmationHtml, renderOrderStatusHtml, type OrderConfirmationData } from "./emailTemplates";
import { generateInvoicePdf, getSellerForInvoice } from "./invoiceData";
import { sendCriticalAlert } from "./alertAdmin";

// Superset of OrderConfirmationData (used for the HTML render) plus the
// address/invoice fields the PDF needs but the email body doesn't —
// avoids threading a second parallel "order" argument through this
// function for what's ultimately one order.
export type OrderConfirmationEmailData = OrderConfirmationData & {
  invoiceNumber: string;
  invoiceIssuedAt: string;
  customerFirstName: string;
  customerLastName: string;
  companyName?: string | null;
  vatId?: string | null;
  vatExempt?: boolean;
  kleinunternehmer?: boolean;
  deliveryMethod: "address" | "packstation";
  street?: string | null;
  packstationNumber?: string | null;
  postNumber?: string | null;
  zip: string;
  city: string;
  country: string;
  hasDifferentShippingAddress?: boolean;
  shippingFirstName?: string | null;
  shippingLastName?: string | null;
  shippingCompanyName?: string | null;
  shippingDeliveryMethod?: "address" | "packstation" | null;
  shippingStreet?: string | null;
  shippingPackstationNumber?: string | null;
  shippingPostNumber?: string | null;
  shippingZip?: string | null;
  shippingCity?: string | null;
  shippingCountry?: string | null;
  shippingContactEmail?: string | null;
  shippingContactPhone?: string | null;
  paymentMethodTitle: string;
};

// Called from app/api/checkout/route.ts right after a successful
// createOrder() — fire-and-forget, must never block or fail the checkout
// response itself. A missing/unpublished template falls back to a plain
// default so a first-ever order isn't silently un-confirmed just because
// nobody's visited the Payload admin yet (mirrors seed-email-templates.ts's
// defaults, kept in sync by hand — there are only two places this wording
// lives, seeding it is a one-time setup step, not a runtime dependency).
//
// The invoice PDF is generated here too (not a separate fire-and-forget
// step) so it can ride along as an attachment on this same send, per the
// "always emailed, not just downloadable" checkout decision — but its own
// failure must not sink the confirmation email itself, so it's wrapped in
// its own try/catch and just sends without the attachment if generation
// fails (still alerted, same severity as the frontend's own critical-error
// path for this checkout flow).
// Shared by sendOrderConfirmationEmail and sendPaymentSwitchedEmail — both
// need to (re)generate the exact same invoice PDF for the exact same
// order, just with a different email body wrapped around it. Regenerated
// fresh each time rather than cached anywhere, same "deterministic
// regeneration, not file storage" approach as the on-demand download
// routes — this also means a switched-payment send picks up the now
// up-to-date paymentMethodTitle, so the PDF's own "✓ Bereits beglichen"
// vs. Vorkasse-notice branch (see @einfach-produktiv/invoicing's
// isPaidImmediately()) reflects the real, current payment state even
// though invoiceNumber/invoiceIssuedAt never change.
async function buildInvoiceAttachment(
  order: OrderConfirmationEmailData,
  seller: Awaited<ReturnType<typeof getSellerForInvoice>>,
): Promise<{ filename: string; content: Buffer }[] | undefined> {
  try {
    const pdf = await generateInvoicePdf(
      {
        orderNumber: order.orderNumber,
        invoiceNumber: order.invoiceNumber,
        invoiceIssuedAt: order.invoiceIssuedAt,
        customerFirstName: order.customerFirstName,
        customerLastName: order.customerLastName,
        companyName: order.companyName,
        vatId: order.vatId,
        vatExempt: order.vatExempt,
        kleinunternehmer: order.kleinunternehmer,
        deliveryMethod: order.deliveryMethod,
        street: order.street,
        packstationNumber: order.packstationNumber,
        postNumber: order.postNumber,
        zip: order.zip,
        city: order.city,
        country: order.country,
        hasDifferentShippingAddress: order.hasDifferentShippingAddress ?? false,
        shippingFirstName: order.shippingFirstName,
        shippingLastName: order.shippingLastName,
        shippingCompanyName: order.shippingCompanyName,
        shippingDeliveryMethod: order.shippingDeliveryMethod,
        shippingStreet: order.shippingStreet,
        shippingPackstationNumber: order.shippingPackstationNumber,
        shippingPostNumber: order.shippingPostNumber,
        shippingZip: order.shippingZip,
        shippingCity: order.shippingCity,
        shippingCountry: order.shippingCountry,
        shippingContactEmail: order.shippingContactEmail,
        shippingContactPhone: order.shippingContactPhone,
        paymentMethodTitle: order.paymentMethodTitle,
        items: order.items.map((i) => ({
          productName: i.productName,
          quantity: i.quantity,
          unitPrice: i.unitPrice,
          taxRatePercent: i.taxRatePercent,
          bundleContents: i.bundleContents ?? null,
          variantName: i.variantName ?? null,
          imageUrl: i.imageUrl ?? null,
          sku: i.sku ?? null,
        })),
        subtotal: order.subtotal,
        shippingCost: order.shippingCost,
        discountAmount: order.discountAmount,
        discountCode: order.discountCode,
        total: order.total,
      },
      seller,
    );
    if (!pdf) throw new Error("generateInvoicePdf returned null (missing invoice-settings?)");
    return [{ filename: `Rechnung-${order.invoiceNumber}.pdf`, content: pdf }];
  } catch (err) {
    sendCriticalAlert("Rechnungs-PDF konnte nicht erzeugt werden", {
      orderNumber: order.orderNumber,
      invoiceNumber: order.invoiceNumber,
      error: String(err),
    });
    return undefined;
  }
}

export async function sendOrderConfirmationEmail(order: OrderConfirmationEmailData, customerEmail: string): Promise<boolean> {
  const fetchedTemplate = await getEmailTemplate("order-confirmation");
  // `active === false` is a deliberate admin decision to suppress this
  // email entirely — distinct from `fetchedTemplate` being null (no row
  // saved yet), which still sends below with the hardcoded default
  // wording. Checked before the fallback is applied, since the fallback
  // object has no `active` field of its own (implicitly always on).
  if (fetchedTemplate && !fetchedTemplate.active) return false;
  const template = fetchedTemplate ?? {
    subject: "Bestellt! Deine Ruhe kann kommen 🎉",
    heading: "Bestellt!",
    bodyText: "Deine Bestellung ist bei uns eingetrudelt — wir kümmern uns schon liebevoll darum, sie für dich zu packen.",
    footerText: null,
  };

  const seller = await getSellerForInvoice();
  const html = renderOrderConfirmationHtml(template, order, seller);
  const attachments = await buildInvoiceAttachment(order, seller);

  await transport.sendMail({
    // SPF confirmed 2026-07-29 for einfach-produktiv.com, and the SMTP
    // account itself switched to a mailbox on that domain — see the
    // backend's sellerInfo.ts buildFromHeader() comment for why both had
    // to move together (Hostinger's relay rejects a From address the
    // authenticated mailbox doesn't own). Reply-To stays set too, though
    // now redundant with From itself pointing at sellerEmail.
    // emailFromName/emailFromAddress (company-settings) are the
    // admin-editable override, same fallback chain as the backend's
    // buildFromHeader().
    from: `"${seller?.emailFromName || seller?.sellerName || "Björn"}" <${seller?.emailFromAddress || seller?.sellerEmail || "hallo@einfach-produktiv.com"}>`,
    replyTo: seller?.sellerEmail || undefined,
    to: customerEmail,
    subject: template.subject,
    html,
    attachments,
  });
  return true;
}

// Sent instead of sendOrderConfirmationEmail() when the confirmed payment
// came from switchPaymentToStripe.ts (an existing Überweisung order the
// customer moved to Kreditkarte/PayPal), not a fresh checkout — see
// confirmPaymentEmail.ts's own branch on order.paymentSwitchedAt. A second
// full "Vielen Dank für deine Bestellung!" email (with its own invoice PDF
// re-attached) would read as a brand-new purchase; this is a short,
// dedicated confirmation instead, same shape as the order-status emails
// (icon + admin-editable text + "Bestellung ansehen" button), no item
// table/invoice attachment — the invoice itself didn't change, only how
// it got paid.
export async function sendPaymentSwitchedEmail(order: OrderConfirmationEmailData, customerEmail: string): Promise<boolean> {
  const fetchedTemplate = await getEmailTemplate("payment-method-switched");
  if (fetchedTemplate && !fetchedTemplate.active) return false;
  const template = fetchedTemplate ?? {
    subject: "Erledigt! Deine Zahlung ist da 🎉",
    heading: "Erledigt!",
    bodyText: "Deine Zahlung ist gerade bei uns eingetrudelt — ab jetzt läuft alles automatisch weiter, du musst dich um nichts mehr kümmern. Deine aktualisierte Rechnung findest du im Anhang.",
    footerText: null,
  };

  const seller = await getSellerForInvoice();
  const html = renderOrderStatusHtml(
    template,
    "💳",
    order.orderNumber,
    `https://einfach-produktiv.mk360.de/konto/bestellungen/${encodeURIComponent(order.orderNumber)}`,
    seller,
  );
  // Same invoiceNumber as always (never re-issued for a switch, see
  // confirmPayment.ts), but paymentMethodTitle now reflects the actually-
  // confirmed instrument — worth a fresh PDF, not the original attachment,
  // since @einfach-produktiv/invoicing's own isPaidImmediately() check
  // reads that title to decide "✓ Bereits beglichen" vs. the Vorkasse
  // notice.
  const attachments = await buildInvoiceAttachment(order, seller);

  await transport.sendMail({
    from: `"${seller?.emailFromName || seller?.sellerName || "Björn"}" <${seller?.emailFromAddress || seller?.sellerEmail || "hallo@einfach-produktiv.com"}>`,
    replyTo: seller?.sellerEmail || undefined,
    to: customerEmail,
    subject: template.subject,
    html,
    attachments,
  });
  return true;
}
