// Nodemailer transport + the branded Blut24 HTML mails.
// Transport mirrors the ERP: localhost:25, no auth, no TLS verification.
//
// Mail HTML rules applied here: table layout, inline styles only, max-width 600px,
// no external images (SVG is stripped by Gmail), a bulletproof padded-link button,
// and a plain-text alternative for every mail.
//
// LANGUAGE: every visitor-facing mail takes a `lang` and is built from
// server/utils/i18n.ts. The value comes from the REGISTRATION ROW, not from the request
// that happens to trigger the mail — someone who registered in English gets English mail
// even if the confirmation link is later opened in a German browser. `buildInternalMail`
// is the exception and stays German: it goes to the operator, not to a visitor.
import nodemailer from 'nodemailer'
import { asLang, serverMessages, type ApiLang } from './i18n'
import { normaliseType } from './registrationTypes'

export const escapeHtml = (value: any): string => String(value ?? '')
  .replace(/&/g, '&amp;')
  .replace(/</g, '&lt;')
  .replace(/>/g, '&gt;')
  .replace(/"/g, '&quot;')
  .replace(/'/g, '&#39;')

let transporter: any = null

export const getTransport = () => {
  if (transporter) return transporter
  const config = useRuntimeConfig()
  transporter = nodemailer.createTransport({
    host: String(config.smtpHost || 'localhost'),
    port: Number(config.smtpPort || 25),
    secure: false,
    tls: { rejectUnauthorized: false },
  })
  return transporter
}

export type MailInput = { to: string, subject: string, html: string, text: string, bcc?: string }

/** Sends a mail. Never throws — a failed send must not roll back a stored registration. */
export const sendMail = async (input: MailInput): Promise<{ ok: boolean, error: string }> => {
  const config = useRuntimeConfig()
  try {
    await getTransport().sendMail({
      from: String(config.mailFrom || 'Blut24 <no-reply@blut24.com>'),
      to: input.to,
      bcc: input.bcc || String(config.mailBcc || '') || undefined,
      subject: input.subject,
      html: input.html,
      text: input.text,
    })
    return { ok: true, error: '' }
  } catch (err: any) {
    console.error('[blut24] E-Mail-Versand fehlgeschlagen:', err?.message || err)
    return { ok: false, error: err?.message || String(err) }
  }
}

// ------------------------------------------------------------------ layout

const RED = '#B71C1C'
const RED_MID = '#C62828'
const BLUE = '#0D47A1'
const INK = '#0F172A'
const MUTED = '#475569'
const SURFACE = '#F8FAFC'
const BORDER = '#E2E8F0'

const layout = (opts: { preheader: string, heading: string, body: string, lang?: ApiLang }) => {
  const lang = asLang(opts.lang)
  const m = serverMessages(lang).mail
  return `<!DOCTYPE html>
<html lang="${m.htmlLang}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Blut24</title>
</head>
<body style="margin:0;padding:0;background:${SURFACE};font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Arial,Helvetica,sans-serif;color:${INK};">
  <div style="display:none;max-height:0;overflow:hidden;opacity:0;color:transparent;">${escapeHtml(opts.preheader)}</div>
  <table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:${SURFACE};padding:24px 12px;">
    <tr>
      <td align="center">
        <table role="presentation" width="600" cellpadding="0" cellspacing="0" border="0" style="width:100%;max-width:600px;background:#ffffff;border:1px solid ${BORDER};border-radius:14px;overflow:hidden;">
          <tr>
            <td style="background:${RED};background-image:linear-gradient(135deg,${RED_MID} 0%,${RED} 60%,${BLUE} 100%);padding:26px 28px;">
              <div style="font-size:22px;line-height:1.2;font-weight:700;color:#ffffff;letter-spacing:0.3px;">Blut24</div>
              <div style="font-size:14px;line-height:1.5;color:#FFE9E9;margin-top:4px;">${escapeHtml(m.brandTagline)}</div>
            </td>
          </tr>
          <tr>
            <td style="padding:30px 28px 10px 28px;">
              <h1 style="margin:0 0 14px 0;font-size:21px;line-height:1.35;font-weight:700;color:${INK};">${escapeHtml(opts.heading)}</h1>
            </td>
          </tr>
          <tr><td style="padding:0 28px 28px 28px;font-size:16px;line-height:1.65;color:${INK};">${opts.body}</td></tr>
          <tr>
            <td style="padding:18px 28px 24px 28px;border-top:1px solid ${BORDER};font-size:13px;line-height:1.6;color:${MUTED};">
              Blut24 &middot; ${escapeHtml(m.brandTagline)}<br>
              ${escapeHtml(m.autoNote)}
            </td>
          </tr>
        </table>
        <div style="max-width:600px;margin:14px auto 0 auto;font-size:12px;line-height:1.6;color:${MUTED};text-align:center;">
          ${m.notRequested}
        </div>
      </td>
    </tr>
  </table>
</body>
</html>`
}

const button = (href: string, label: string) => `
  <table role="presentation" cellpadding="0" cellspacing="0" border="0" style="margin:6px 0 22px 0;">
    <tr>
      <td align="center" style="background:${RED};border-radius:10px;">
        <a href="${escapeHtml(href)}" style="display:inline-block;padding:15px 30px;font-size:16px;line-height:1.2;font-weight:700;color:#ffffff;text-decoration:none;border-radius:10px;">${escapeHtml(label)}</a>
      </td>
    </tr>
  </table>`

const infoRow = (label: string, value: string) => value
  ? `<tr>
      <td style="padding:7px 12px;font-size:14px;color:${MUTED};white-space:nowrap;vertical-align:top;">${escapeHtml(label)}</td>
      <td style="padding:7px 12px;font-size:14px;color:${INK};font-weight:600;vertical-align:top;">${escapeHtml(value)}</td>
     </tr>`
  : ''

// ------------------------------------------------------------------ mails

export type ConfirmationMailInput = {
  /** Registration type key — selects the wording block below. */
  type?: string
  to: string
  contactName: string
  typeLabel: string
  orgName: string
  address: string
  confirmUrl: string
  needsManualApproval: boolean
  /** Language stored on the registration row. Defaults to German. */
  lang?: string
}

/**
 * Double-opt-in mail with the token link.
 *
 * What it says about the registration differs per type: a courier is not a clinic — it
 * has no Standort, no blood stock and no Konserven, so the clinic wording would simply be
 * wrong for them. The per-type blocks live in server/utils/i18n.ts (`mail.types`).
 *
 * The key is normalised before the lookup so a retired type ('abgebende_klinik',
 * 'beziehende_klinik') still gets the clinic block. Without it the `??` fallback would
 * silently drop the mail's main explanatory paragraph — the mail would still send, just
 * with a hole in it, in both the HTML and the plain-text alternative.
 */
export const buildConfirmationMail = (input: ConfirmationMailInput) => {
  const lang = asLang(input.lang)
  const m = serverMessages(lang).mail
  const c = m.confirmation
  const greeting = escapeHtml(m.greeting(input.contactName || ''))
  const rawType = String(input.type ?? '')
  const meta = m.types[rawType] ?? m.types[normaliseType(rawType)] ?? {
    label: input.typeLabel, orgRow: m.fallbackOrgRow, text: '',
  }
  const manual = input.needsManualApproval
    ? `<p style="margin:0 0 16px 0;padding:14px 16px;background:#FFF4F4;border-left:4px solid ${RED_MID};border-radius:0 8px 8px 0;font-size:15px;line-height:1.6;color:${INK};">
         <strong>${escapeHtml(c.manualNoticeLabel)}</strong>${escapeHtml(c.manualNotice)}
       </p>`
    : ''

  const body = `
    <p style="margin:0 0 16px 0;">${greeting}</p>
    <p style="margin:0 0 20px 0;">${c.intro}</p>
    <p style="margin:0 0 20px 0;">${escapeHtml(meta.text)}</p>
    ${button(input.confirmUrl, c.button)}
    <p style="margin:0 0 18px 0;font-size:14px;color:${MUTED};">
      ${escapeHtml(c.linkFallback)}<br>
      <span style="word-break:break-all;color:${BLUE};">${escapeHtml(input.confirmUrl)}</span>
    </p>
    ${manual}
    <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="background:${SURFACE};border:1px solid ${BORDER};border-radius:10px;margin:6px 0 4px 0;">
      ${infoRow(c.rowType, meta.label)}
      ${infoRow(meta.orgRow, input.orgName)}
      ${infoRow(c.rowAddress, input.address)}
      ${infoRow(c.rowEmail, input.to)}
    </table>
    <p style="margin:18px 0 0 0;font-size:14px;color:${MUTED};">
      ${escapeHtml(c.validity)}
    </p>`

  const text = [
    m.greeting(input.contactName || ''),
    '',
    c.textIntro,
    c.textLinkLead,
    input.confirmUrl,
    '',
    meta.text,
    meta.text ? '' : null,
    c.textRegisteredAs(meta.label),
    `${meta.orgRow}: ${input.orgName}`,
    input.address ? c.textAddress(input.address) : '',
    '',
    input.needsManualApproval ? c.textManual : '',
    c.validity,
    '',
    c.footer,
  ].filter((l) => l !== '').join('\n')

  return {
    subject: c.subject,
    html: layout({ preheader: c.preheader, heading: c.heading, body, lang }),
    text,
  }
}

export type WelcomeMailInput = {
  to: string
  contactName: string
  orgName: string
  typeLabel: string
  needsManualApproval: boolean
  credentialsSent: boolean
  /** Language stored on the registration row. Defaults to German. */
  lang?: string
}

/**
 * Sent after a successful confirmation.
 *
 * The "what happens next" sentence has THREE states and the order below is the honest one.
 * Since registrations are activated automatically wherever the validator can decide them
 * (see server/api/registration/submit.post.ts), `credentialsSent` is the normal case and
 * `manual` is the exception — the opposite of how this read before:
 *
 *   credentialsSent   → the ERP created the account and has already mailed the credentials.
 *                       Say the access is ready; do NOT promise a manual review that will
 *                       never happen.
 *   needsManualApproval → nothing could be verified (clinic without a domain on record, or
 *                       a courier). A human really does look at it.
 *   otherwise         → auto-activation was intended but the credentials mail has not gone
 *                       out (ERP disabled, or the call failed and operations will retry).
 *                       Promise the separate mail, not a review.
 *
 * `credentialsSent` deliberately outranks `needsManualApproval`: if credentials are already
 * in the recipient's inbox, telling them to wait for a review would be plainly wrong.
 */
export const buildWelcomeMail = (input: WelcomeMailInput) => {
  const lang = asLang(input.lang)
  const m = serverMessages(lang).mail
  const w = m.welcome
  const greeting = escapeHtml(m.greeting(input.contactName || ''))
  const next = input.credentialsSent
    ? w.credentials
    : input.needsManualApproval ? w.manual : w.pending

  const body = `
    <p style="margin:0 0 16px 0;">${greeting}</p>
    <p style="margin:0 0 16px 0;">
      ${w.confirmed(escapeHtml(input.orgName), escapeHtml(input.typeLabel))}
    </p>
    <p style="margin:0 0 16px 0;">${escapeHtml(next)}</p>
    <p style="margin:0 0 4px 0;font-weight:600;">${escapeHtml(w.listTitle)}</p>
    <ul style="margin:0 0 16px 0;padding-left:20px;line-height:1.7;">
      ${w.list.map((item) => `<li>${item}</li>`).join('\n      ')}
    </ul>`

  const text = [
    m.greeting(input.contactName || ''),
    '',
    `${input.orgName} — ${input.typeLabel}`,
    input.credentialsSent
      ? w.textCredentials
      : input.needsManualApproval ? w.textManual : w.textPending,
    '',
    m.confirmation.footer,
  ].join('\n')

  return {
    subject: w.subject,
    html: layout({ preheader: w.preheader, heading: w.heading, body, lang }),
    text,
  }
}

export type DuplicateAttemptMailInput = {
  contactName: string
  orgName: string
  attemptedEmail: string
  attemptedAt: string
  /** Language stored on the EXISTING registration — this mail goes to its owner. */
  lang?: string
}

/**
 * Sent to the ALREADY-REGISTERED contact when someone tries to register the same
 * facility again.
 *
 * The person attempting registration is deliberately told nothing — they get the
 * same neutral "check your inbox" response as a first-time registrant, so the form
 * cannot be used to discover which clinics are already on Blut24. The real account
 * holder is the one who gets informed, because they are the only party entitled to
 * know and the only one who can act on it (a colleague signing up, or an abuse
 * attempt).
 *
 * We show the attempted address so the owner can recognise a colleague, but we do
 * not include any link that would let this mail be used to take over the account.
 */
export const buildDuplicateAttemptMail = (input: DuplicateAttemptMailInput) => {
  const lang = asLang(input.lang)
  const m = serverMessages(lang).mail
  const d = m.duplicate
  const greeting = escapeHtml(m.greeting(input.contactName || ''))
  const body = `
    <p style="margin:0 0 16px 0;">${greeting}</p>
    <p style="margin:0 0 20px 0;">${d.intro(escapeHtml(input.orgName))}</p>
    <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="background:${SURFACE};border:1px solid ${BORDER};border-radius:10px;">
      ${infoRow(d.rowTime, input.attemptedAt)}
      ${infoRow(d.rowEmail, input.attemptedEmail)}
    </table>
    <p style="margin:20px 0 16px 0;">${d.reassure}</p>
    <p style="margin:0 0 8px 0;font-size:14px;color:${MUTED};">${escapeHtml(d.unknown)}</p>`
  return {
    subject: d.subject,
    html: layout({ preheader: d.preheader, heading: d.subject, body, lang }),
    text: [
      m.greeting(input.contactName || ''),
      '',
      `${input.orgName} — Blut24`,
      `${d.rowTime}: ${input.attemptedAt}`,
      `${d.rowEmail}: ${input.attemptedEmail}`,
      '',
      d.reassureLead,
      d.unknown,
    ].join('\n'),
  }
}

/**
 * Internal notification (operations inbox) — plain and information-dense.
 * Deliberately German-only: the recipient is the operator, not a visitor.
 */
export const buildInternalMail = (subject: string, rows: Array<[string, string]>, note = '') => {
  const body = `
    ${note ? `<p style="margin:0 0 16px 0;">${escapeHtml(note)}</p>` : ''}
    <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="background:${SURFACE};border:1px solid ${BORDER};border-radius:10px;">
      ${rows.map(([k, v]) => infoRow(k, v)).join('')}
    </table>`
  return {
    subject,
    html: layout({ preheader: subject, heading: subject, body, lang: 'de' }),
    text: [note, ...rows.map(([k, v]) => `${k}: ${v}`)].filter(Boolean).join('\n'),
  }
}
