import nodemailer from 'nodemailer'
import type { Transporter } from 'nodemailer'
import { prisma } from '@/lib/prisma'

/**
 * Dev email override: when DEV_EMAIL_OVERRIDE is set, ALL outgoing emails
 * are redirected to that address. The original recipient is noted in the subject.
 */
const DEV_EMAIL_OVERRIDE = process.env.DEV_EMAIL_OVERRIDE || ''

async function sendEmail(opts: { to: string; subject: string; text: string; html: string }): Promise<void> {
  // Hard guard: never send real email from the test runner. This is a belt-and-
  // braces check on top of the vitest-level mock in tests/setup.ts. Vitest sets
  // NODE_ENV='test' and exposes VITEST=true automatically.
  if (process.env.NODE_ENV === 'test' || process.env.VITEST === 'true') {
    return
  }
  const { transporter, from } = await getTransporter()
  const to = DEV_EMAIL_OVERRIDE || opts.to
  const subject = DEV_EMAIL_OVERRIDE ? `[DEV → ${opts.to}] ${opts.subject}` : opts.subject
  await transporter.sendMail({ from, to, subject, text: opts.text, html: opts.html })
}

// Cached transporter and config hash to detect changes
let cachedTransporter: Transporter | null = null
let cachedConfigHash = ''
let cachedFrom = ''
let cachedAt = 0
const CACHE_TTL = 60_000 // 1 minute

/**
 * Get SMTP transporter using database settings with env var fallback.
 * Caches the transporter and rebuilds it when settings change.
 * Uses connection pooling for reliable bulk sends.
 */
async function getTransporter(): Promise<{ transporter: Transporter; from: string }> {
  // Fast path: return cached transporter if still fresh
  if (cachedTransporter && Date.now() - cachedAt < CACHE_TTL) {
    return { transporter: cachedTransporter, from: cachedFrom }
  }

  // Read DB settings
  const dbSettings = await prisma.systemSettings.findMany({
    where: {
      key: { in: ['smtp_host', 'smtp_port', 'smtp_user', 'smtp_password', 'email_from_name', 'email_from'] },
    },
    select: { key: true, value: true },
  })

  const db: Record<string, string> = {}
  for (const s of dbSettings) {
    db[s.key] = s.value
  }

  // DB settings take priority, env vars as fallback
  const host = db.smtp_host || process.env.SMTP_HOST || 'localhost'
  const port = db.smtp_port || process.env.SMTP_PORT || '587'
  const user = db.smtp_user || process.env.SMTP_USER || ''
  const pass = db.smtp_password || process.env.SMTP_PASS || ''

  // Combine sender name and email into "Name <email>" format
  const fromName = db.email_from_name || 'MOPC Portal'
  const rawFromEmail = db.email_from || process.env.EMAIL_FROM || 'noreply@monaco-opc.com'
  // Strip "Name <...>" wrapper if present — extract just the email address
  const fromEmail = rawFromEmail.includes('<')
    ? rawFromEmail.match(/<([^>]+)>/)?.[1] || rawFromEmail
    : rawFromEmail
  const from = `${fromName} <${fromEmail}>`

  // Check if config changed since last call
  const configHash = `${host}:${port}:${user}:${pass}:${from}`
  if (cachedTransporter && configHash === cachedConfigHash) {
    cachedAt = Date.now()
    return { transporter: cachedTransporter, from: cachedFrom }
  }

  // Close old transporter if it exists (clean up pooled connections)
  if (cachedTransporter) {
    try { cachedTransporter.close() } catch { /* ignore */ }
  }

  // Create new transporter with connection pooling for reliable bulk sends
  cachedTransporter = nodemailer.createTransport({
    host,
    port: parseInt(port),
    secure: port === '465',
    auth: { user, pass },
    pool: true,
    maxConnections: 5,
    maxMessages: 10,
    socketTimeout: 30_000,
    connectionTimeout: 15_000,
  } as nodemailer.TransportOptions)
  cachedConfigHash = configHash
  cachedFrom = from
  cachedAt = Date.now()

  return { transporter: cachedTransporter, from: cachedFrom }
}

/**
 * Delay helper for throttling bulk email sends.
 * Prevents overwhelming the SMTP server (Poste.io).
 */
export function emailDelay(ms = 150): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

// Legacy references for backward compat — default sender from env
const defaultFrom = process.env.EMAIL_FROM || 'MOPC Portal <noreply@monaco-opc.com>'

// =============================================================================
// Helpers
// =============================================================================

/**
 * Escape user-supplied strings for safe injection into HTML email templates.
 * Prevents XSS if email content is rendered in a webmail client.
 */
function escapeHtml(str: string): string {
  return str
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;')
}

/**
 * Get the base URL for links in emails.
 * Uses NEXTAUTH_URL with a safe production fallback.
 */
export function getBaseUrl(): string {
  return process.env.NEXTAUTH_URL || 'https://portal.monaco-opc.com'
}

/**
 * Ensure a URL is absolute (has protocol + host).
 * Converts relative paths like "/jury/competitions" to full URLs.
 */
export function ensureAbsoluteUrl(url: string | undefined): string | undefined {
  if (!url) return undefined
  if (url.startsWith('http://') || url.startsWith('https://')) return url
  if (url.startsWith('/')) return `${getBaseUrl()}${url}`
  return `${getBaseUrl()}/${url}`
}

// =============================================================================
// Brand Colors & Logo URLs
// =============================================================================

const BRAND = {
  red: '#de0f1e',
  redHover: '#b91c1c',
  darkBlue: '#053d57',
  teal: '#557f8c',
  white: '#fefefe',
  lightGray: '#f5f5f5',
  textDark: '#1f2937',
  textMuted: '#6b7280',
}

const getSmallLogoUrl = () => 'https://s3.monaco-opc.com/public/MOPC-blue-small.png'
const getBigLogoUrl = () => 'https://s3.monaco-opc.com/public/MOPC-blue-long.png'

// =============================================================================
// Email Template Wrapper & Helpers
// =============================================================================

/**
 * Wrap email content with consistent branding:
 * - Small logo at top of white content box
 * - Big logo in dark blue footer
 */
function getEmailWrapper(content: string): string {
  return `
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>MOPC</title>
  <!--[if mso]>
  <noscript>
    <xml>
      <o:OfficeDocumentSettings>
        <o:PixelsPerInch>96</o:PixelsPerInch>
      </o:OfficeDocumentSettings>
    </xml>
  </noscript>
  <![endif]-->
</head>
<body style="margin: 0; padding: 0; background-color: ${BRAND.darkBlue}; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased;">
  <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="background-image: url('https://s3.monaco-opc.com/public/ocean.png'); background-size: cover; background-position: center top; background-repeat: no-repeat; background-color: ${BRAND.darkBlue};">
    <tr>
      <td align="center" style="padding: 40px 20px;">
        <!-- Main Container -->
        <table role="presentation" width="600" cellspacing="0" cellpadding="0" border="0" style="max-width: 600px; width: 100%;">

          <!-- Content Box -->
          <tr>
            <td style="background-color: ${BRAND.white}; border-radius: 12px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);">
              <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
                <!-- Small Logo Header -->
                <tr>
                  <td align="center" style="padding: 32px 40px 24px 40px;">
                    <img src="${getSmallLogoUrl()}" alt="MOPC" width="100" height="auto" style="display: block; border: 0; max-width: 100px;">
                  </td>
                </tr>
                <!-- Email Content -->
                <tr>
                  <td style="padding: 0 40px 32px 40px;">
                    ${content}
                  </td>
                </tr>
                <!-- Footer -->
                <tr>
                  <td style="padding: 0 40px 32px 40px; border-top: 1px solid #e5e7eb;">
                    <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
                      <tr>
                        <td align="center" style="padding-top: 24px;">
                          <img src="${getBigLogoUrl()}" alt="Monaco Ocean Protection Challenge" width="180" height="auto" style="display: block; border: 0; max-width: 180px; margin-bottom: 12px;">
                        </td>
                      </tr>
                      <tr>
                        <td align="center">
                          <p style="color: ${BRAND.textMuted}; font-size: 13px; margin: 0; line-height: 1.5;">
                            Together for a healthier ocean
                          </p>
                          <p style="color: ${BRAND.textMuted}; font-size: 12px; margin: 8px 0 0 0;">
                            &copy; ${new Date().getFullYear()} Monaco Ocean Protection Challenge
                          </p>
                        </td>
                      </tr>
                    </table>
                  </td>
                </tr>
              </table>
            </td>
          </tr>

        </table>
      </td>
    </tr>
  </table>
</body>
</html>
`
}

/**
 * Generate a styled CTA button
 */
function ctaButton(url: string, text: string): string {
  // Ensure URL is always absolute for email clients
  const safeUrl = ensureAbsoluteUrl(url) || url
  return `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 24px 0;">
  <tr>
    <td align="center">
      <table role="presentation" cellspacing="0" cellpadding="0" border="0">
        <tr>
          <td align="center" bgcolor="${BRAND.red}" style="background-color: ${BRAND.red}; border-radius: 8px; mso-border-alt: none;">
            <a href="${safeUrl}" target="_blank" style="display: inline-block; padding: 16px 40px; color: #ffffff; text-decoration: none; font-weight: 600; font-size: 16px; font-family: Helvetica, Arial, sans-serif; mso-line-height-rule: exactly; line-height: 20px;">
              ${text}
            </a>
          </td>
        </tr>
      </table>
    </td>
  </tr>
  <tr>
    <td align="center" style="padding-top: 8px;">
      <p style="margin: 0; font-size: 12px; color: ${BRAND.textMuted};">
        If the button doesn't work: <a href="${safeUrl}" target="_blank" style="color: ${BRAND.teal}; word-break: break-all;">${safeUrl}</a>
      </p>
    </td>
  </tr>
</table>
`
}

/**
 * Generate styled section title
 */
function sectionTitle(text: string): string {
  return `<h2 style="color: ${BRAND.darkBlue}; margin: 0 0 16px 0; font-size: 22px; font-weight: 600; line-height: 1.3;">${escapeHtml(text)}</h2>`
}

/**
 * Generate styled paragraph
 */
function paragraph(text: string): string {
  return `<p style="color: ${BRAND.textDark}; margin: 0 0 16px 0; font-size: 15px; line-height: 1.6;">${text}</p>`
}

/**
 * Generate styled info box
 */
function infoBox(content: string, variant: 'warning' | 'info' | 'success' = 'info'): string {
  const colors = {
    warning: { bg: '#fef3c7', border: '#f59e0b', text: '#92400e' },
    info: { bg: '#e0f2fe', border: '#0ea5e9', text: '#0369a1' },
    success: { bg: '#dcfce7', border: '#22c55e', text: '#166534' },
  }
  const c = colors[variant]
  return `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: ${c.bg}; border-left: 4px solid ${c.border}; border-radius: 0 8px 8px 0; padding: 16px 20px;">
      <p style="color: ${c.text}; margin: 0; font-size: 14px; font-weight: 500;">${content}</p>
    </td>
  </tr>
</table>
`
}

/**
 * Generate styled stat card
 */
function statCard(label: string, value: string | number): string {
  return `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: ${BRAND.lightGray}; border-radius: 12px; padding: 24px; text-align: center;">
      <p style="color: ${BRAND.textMuted}; margin: 0 0 8px 0; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">${escapeHtml(label)}</p>
      <p style="color: ${BRAND.darkBlue}; margin: 0; font-size: 42px; font-weight: 700; line-height: 1;">${escapeHtml(String(value))}</p>
    </td>
  </tr>
</table>
`
}

// =============================================================================
// Email Templates
// =============================================================================

export interface EmailTemplate {
  subject: string
  html: string
  text: string
}

/**
 * Generate magic link email template
 */
function getMagicLinkTemplate(url: string, expiryMinutes: number = 15): EmailTemplate {
  const content = `
    ${sectionTitle('Sign in to your account')}
    ${paragraph('Click the button below to securely sign in to the MOPC Portal.')}
    ${infoBox(`<strong>This link expires in ${expiryMinutes} minutes</strong>`, 'warning')}
    ${ctaButton(url, 'Sign In to MOPC')}
    <p style="color: ${BRAND.textMuted}; margin: 24px 0 0 0; font-size: 13px; text-align: center;">
      If you didn't request this email, you can safely ignore it.
    </p>
  `

  return {
    subject: 'Sign in to MOPC Portal',
    html: getEmailWrapper(content),
    text: `
Sign in to MOPC Portal
=========================

Click the link below to sign in to your account:

${url}

This link will expire in ${expiryMinutes} minutes.

If you didn't request this email, you can safely ignore it.

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate password reset email template
 */
function getPasswordResetTemplate(url: string, expiryMinutes: number = 30): EmailTemplate {
  const content = `
    ${sectionTitle('Reset your password')}
    ${paragraph('We received a request to reset your password for the MOPC Portal. Click the button below to choose a new password.')}
    ${infoBox(`<strong>This link expires in ${expiryMinutes} minutes</strong>`, 'warning')}
    ${ctaButton(url, 'Reset Password')}
    <p style="color: ${BRAND.textMuted}; margin: 24px 0 0 0; font-size: 13px; text-align: center;">
      If you didn't request a password reset, you can safely ignore this email. Your password will not change.
    </p>
  `

  return {
    subject: 'Reset your password — MOPC Portal',
    html: getEmailWrapper(content),
    text: `
Reset your password
=========================

Click the link below to reset your password:

${url}

This link will expire in ${expiryMinutes} minutes.

If you didn't request this, you can safely ignore this email.

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate generic invitation email template (not round-specific)
 */
function formatExpiryLabel(hours: number): string {
  if (hours < 24) return `${hours} hour${hours !== 1 ? 's' : ''}`
  const days = Math.round(hours / 24)
  return `${days} day${days !== 1 ? 's' : ''}`
}

function getGenericInvitationTemplate(
  name: string,
  url: string,
  role: string,
  expiryHours: number = 72
): EmailTemplate {
  const roleLabel = role === 'JURY_MEMBER' ? 'jury member' : role.toLowerCase().replace('_', ' ')
  const article = /^[aeiou]/i.test(roleLabel) ? 'an' : 'a'
  const greeting = name ? `Hello ${name},` : 'Hello,'
  const expiryLabel = formatExpiryLabel(expiryHours)

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(`You've been invited to join the Monaco Ocean Protection Challenge platform as ${article} <strong>${roleLabel}</strong>.`)}
    ${paragraph('Click the button below to set up your account and get started.')}
    ${ctaButton(url, 'Accept Invitation')}
    ${infoBox(`This link will expire in ${expiryLabel}.`, 'info')}
  `

  return {
    subject: "You're invited to join the MOPC Portal",
    html: getEmailWrapper(content),
    text: `
${greeting}

You've been invited to join the Monaco Ocean Protection Challenge platform as ${article} ${roleLabel}.

Click the link below to set up your account and get started:

${url}

This link will expire in ${expiryLabel}.

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate evaluation reminder email template
 */
function getEvaluationReminderTemplate(
  name: string,
  pendingCount: number,
  roundName: string,
  deadline: string,
  assignmentsUrl: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  // Deadline alert box (styled differently from info box)
  const deadlineBox = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: #fef2f2; border-left: 4px solid ${BRAND.red}; border-radius: 0 8px 8px 0; padding: 16px 20px;">
      <p style="color: #991b1b; margin: 0 0 4px 0; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">Deadline</p>
      <p style="color: #7f1d1d; margin: 0; font-size: 16px; font-weight: 700;">${escapeHtml(deadline)}</p>
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(`This is a friendly reminder about your pending evaluations for <strong style="color: ${BRAND.darkBlue};">${escapeHtml(roundName)}</strong>.`)}
    ${statCard('Pending Evaluations', pendingCount)}
    ${deadlineBox}
    ${paragraph('Your expert evaluation helps identify the most promising ocean conservation projects. Please complete your reviews before the deadline.')}
    ${ctaButton(assignmentsUrl, 'View My Assignments')}
  `

  return {
    subject: `Reminder: ${pendingCount} evaluation${pendingCount !== 1 ? 's' : ''} awaiting your review`,
    html: getEmailWrapper(content),
    text: `
${greeting}

This is a friendly reminder that you have ${pendingCount} pending evaluation${pendingCount !== 1 ? 's' : ''} for ${roundName}.

Deadline: ${deadline}

Please complete your evaluations before the deadline to ensure your feedback is included in the selection process.

View your assignments: ${assignmentsUrl}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate announcement email template
 */
function getAnnouncementTemplate(
  name: string,
  title: string,
  message: string,
  ctaText?: string,
  ctaUrl?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'
  const ctaTextPlain = ctaText && ctaUrl ? `\n${ctaText}: ${ctaUrl}\n` : ''

  // Escape HTML in message but preserve line breaks
  const formattedMessage = escapeHtml(message).replace(/\n/g, '<br>')

  // Title card with success styling
  const titleCard = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: #ecfdf5; border-left: 4px solid #059669; border-radius: 0 12px 12px 0; padding: 20px 24px;">
      <h3 style="color: #065f46; margin: 0; font-size: 18px; font-weight: 700;">${escapeHtml(title)}</h3>
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle(greeting)}
    ${titleCard}
    <div style="color: ${BRAND.textDark}; font-size: 15px; line-height: 1.7; margin: 20px 0;">
      ${formattedMessage}
    </div>
    ${ctaText && ctaUrl ? ctaButton(ctaUrl, ctaText) : ''}
  `

  return {
    subject: title,
    html: getEmailWrapper(content),
    text: `
${greeting}

${title}

${message}
${ctaTextPlain}
---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate award juror notification template — used when an admin assigns a
 * juror to a special award and when sending follow-up reminders. Tells the
 * juror what the award is, how many projects are eligible, and links them
 * straight to the voting page.
 */
function getAwardJurorNotificationTemplate(
  name: string,
  awardName: string,
  url: string,
  options?: {
    eligibleCount?: number
    votingEndAt?: Date | null
    customMessage?: string
    isReminder?: boolean
  },
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'
  const eligibleCount = options?.eligibleCount
  const votingEndAt = options?.votingEndAt
  const customMessage = options?.customMessage?.trim()
  const isReminder = options?.isReminder ?? false

  const lead = isReminder
    ? `This is a reminder that you've been assigned as a juror for <strong style="color: ${BRAND.darkBlue};">${escapeHtml(awardName)}</strong>.`
    : `You've been assigned as a juror for <strong style="color: ${BRAND.darkBlue};">${escapeHtml(awardName)}</strong>.`

  const projectsLine = typeof eligibleCount === 'number' && eligibleCount > 0
    ? paragraph(`There ${eligibleCount === 1 ? 'is' : 'are'} <strong>${eligibleCount}</strong> eligible project${eligibleCount === 1 ? '' : 's'} for you to review.`)
    : ''

  const deadlineLine = votingEndAt
    ? paragraph(`<strong>Voting closes:</strong> ${escapeHtml(votingEndAt.toLocaleString('en-GB', { dateStyle: 'long', timeStyle: 'short' }))}`)
    : ''

  const customMessageHtml = customMessage
    ? `<div style="color: ${BRAND.textDark}; font-size: 15px; line-height: 1.7; margin: 20px 0; padding: 20px; background-color: ${BRAND.lightGray}; border-radius: 8px;">${escapeHtml(customMessage).replace(/\n/g, '<br>')}</div>`
    : ''

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(lead)}
    ${projectsLine}
    ${deadlineLine}
    ${customMessageHtml}
    ${ctaButton(url, 'Review & Vote')}
    <p style="color: ${BRAND.textMuted}; margin: 20px 0 0 0; font-size: 13px; text-align: center;">
      Sign in with your existing MOPC credentials to access the voting page.
    </p>
  `

  return {
    subject: isReminder
      ? `Reminder: vote for the ${awardName}`
      : `You've been assigned as a juror for ${awardName}`,
    html: getEmailWrapper(content),
    text: `
${greeting}

${isReminder ? 'This is a reminder that you' : 'You'}'ve been assigned as a juror for ${awardName}.
${typeof eligibleCount === 'number' && eligibleCount > 0 ? `\nThere ${eligibleCount === 1 ? 'is' : 'are'} ${eligibleCount} eligible project${eligibleCount === 1 ? '' : 's'} for you to review.` : ''}${votingEndAt ? `\nVoting closes: ${votingEndAt.toLocaleString('en-GB', { dateStyle: 'long', timeStyle: 'short' })}` : ''}
${customMessage ? `\n${customMessage}\n` : ''}
Review & vote: ${url}

Sign in with your existing MOPC credentials to access the voting page.

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate jury invitation email template
 */
function getJuryInvitationTemplate(
  name: string,
  url: string,
  roundName: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(`You've been invited to serve as a jury member for <strong style="color: ${BRAND.darkBlue};">${escapeHtml(roundName)}</strong>.`)}
    ${paragraph('As a jury member, you\'ll evaluate innovative ocean protection projects and help select the most promising initiatives.')}
    ${ctaButton(url, 'Accept Invitation')}
    <p style="color: ${BRAND.textMuted}; margin: 20px 0 0 0; font-size: 13px; text-align: center;">
      This link will allow you to access the platform and view your assigned projects.
    </p>
  `

  return {
    subject: `You're invited to evaluate projects for ${roundName}`,
    html: getEmailWrapper(content),
    text: `
${greeting}

You've been invited to serve as a jury member for ${roundName}.

As a jury member, you'll evaluate innovative ocean protection projects and help select the most promising initiatives.

Click the link below to accept your invitation:

${url}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate application confirmation email template
 */
function getApplicationConfirmationTemplate(
  name: string,
  projectName: string,
  programName: string,
  customMessage?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  const customMessageHtml = customMessage
    ? `<div style="color: ${BRAND.textDark}; font-size: 15px; line-height: 1.7; margin: 20px 0; padding: 20px; background-color: ${BRAND.lightGray}; border-radius: 8px;">${escapeHtml(customMessage).replace(/\n/g, '<br>')}</div>`
    : ''

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(`Thank you for submitting your application to <strong style="color: ${BRAND.darkBlue};">${escapeHtml(programName)}</strong>!`)}
    ${infoBox(`Your project "<strong>${escapeHtml(projectName)}</strong>" has been successfully received.`, 'success')}
    ${customMessageHtml}
    ${paragraph('Our team will review your submission and get back to you soon. In the meantime, if you have any questions, please don\'t hesitate to reach out.')}
    <p style="color: ${BRAND.textMuted}; margin: 24px 0 0 0; font-size: 13px; text-align: center;">
      You will receive email updates about your application status.
    </p>
  `

  return {
    subject: `Application Received - ${projectName}`,
    html: getEmailWrapper(content),
    text: `
${greeting}

Thank you for submitting your application to ${programName}!

Your project "${projectName}" has been successfully received.

${customMessage || ''}

Our team will review your submission and get back to you soon. In the meantime, if you have any questions, please don't hesitate to reach out.

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate team member invite email template
 */
function getTeamMemberInviteTemplate(
  name: string,
  projectName: string,
  teamLeadName: string,
  inviteUrl: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(`<strong>${escapeHtml(teamLeadName)}</strong> has invited you to join their team for the project "<strong style="color: ${BRAND.darkBlue};">${escapeHtml(projectName)}</strong>" on the Monaco Ocean Protection Challenge platform.`)}
    ${paragraph('Click the button below to accept the invitation and set up your account.')}
    ${ctaButton(inviteUrl, 'Accept Invitation')}
    ${infoBox('This invitation link will expire in 30 days.', 'info')}
    <p style="color: ${BRAND.textMuted}; margin: 24px 0 0 0; font-size: 13px; text-align: center;">
      If you weren't expecting this invitation, you can safely ignore this email.
    </p>
  `

  return {
    subject: `You've been invited to join "${projectName}"`,
    html: getEmailWrapper(content),
    text: `
${greeting}

${teamLeadName} has invited you to join their team for the project "${projectName}" on the Monaco Ocean Protection Challenge platform.

Click the link below to accept the invitation and set up your account:

${inviteUrl}

This invitation link will expire in 30 days.

If you weren't expecting this invitation, you can safely ignore this email.

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

// =============================================================================
// Notification Email Templates
// =============================================================================

/**
 * Context passed to notification email templates
 */
export interface NotificationEmailContext {
  name?: string
  title: string
  message: string
  linkUrl?: string
  linkLabel?: string
  metadata?: Record<string, unknown>
}

/**
 * Generate "Advanced to Semi-Finals" email template
 */
function getAdvancedSemifinalTemplate(
  name: string,
  projectName: string,
  programName: string,
  nextSteps?: string
): EmailTemplate {
  const greeting = name ? `Congratulations ${name}!` : 'Congratulations!'

  const celebrationBanner = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background: linear-gradient(135deg, #059669 0%, #0d9488 100%); border-radius: 12px; padding: 24px; text-align: center;">
      <p style="color: #ffffff; margin: 0 0 8px 0; font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 2px;">Exciting News</p>
      <h2 style="color: #ffffff; margin: 0; font-size: 28px; font-weight: 700;">You're a Semi-Finalist!</h2>
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle(greeting)}
    ${celebrationBanner}
    ${paragraph(`Your project <strong style="color: ${BRAND.darkBlue};">"${escapeHtml(projectName)}"</strong> has been selected to advance to the semi-finals of ${escapeHtml(programName)}.`)}
    ${infoBox('Your innovative approach to ocean protection stood out among hundreds of submissions.', 'success')}
    ${nextSteps ? paragraph(`<strong>Next Steps:</strong> ${escapeHtml(nextSteps)}`) : paragraph('Our team will be in touch shortly with details about the next phase of the competition.')}
  `

  return {
    subject: `Congratulations! "${projectName}" advances to Semi-Finals`,
    html: getEmailWrapper(content),
    text: `
${greeting}

Your project "${projectName}" has been selected to advance to the semi-finals of ${programName}.

Your innovative approach to ocean protection stood out among hundreds of submissions.

${nextSteps || 'Our team will be in touch shortly with details about the next phase of the competition.'}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Selected as Finalist" email template
 */
function getAdvancedFinalTemplate(
  name: string,
  projectName: string,
  programName: string,
  nextSteps?: string
): EmailTemplate {
  const greeting = name ? `Incredible news, ${name}!` : 'Incredible news!'

  const celebrationBanner = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background: linear-gradient(135deg, ${BRAND.darkBlue} 0%, #0891b2 100%); border-radius: 12px; padding: 24px; text-align: center;">
      <p style="color: #ffffff; margin: 0 0 8px 0; font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 2px;">Outstanding Achievement</p>
      <h2 style="color: #ffffff; margin: 0; font-size: 28px; font-weight: 700;">You're a Finalist!</h2>
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle(greeting)}
    ${celebrationBanner}
    ${paragraph(`Your project <strong style="color: ${BRAND.darkBlue};">"${escapeHtml(projectName)}"</strong> has been selected as a <strong>Finalist</strong> in ${escapeHtml(programName)}.`)}
    ${infoBox('You are now among the top projects competing for the grand prize!', 'success')}
    ${nextSteps ? paragraph(`<strong>What Happens Next:</strong> ${escapeHtml(nextSteps)}`) : paragraph('Prepare for the final stage of the competition. Our team will contact you with details about the finalist presentations and judging.')}
  `

  return {
    subject: `You're a Finalist! "${projectName}" selected for finals`,
    html: getEmailWrapper(content),
    text: `
${greeting}

Your project "${projectName}" has been selected as a Finalist in ${programName}.

You are now among the top projects competing for the grand prize!

${nextSteps || 'Prepare for the final stage of the competition. Our team will contact you with details about the finalist presentations and judging.'}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Mentor Assigned" email template (for team)
 */
function getMentorAssignedTemplate(
  name: string,
  projectName: string,
  mentorName: string,
  mentorBio?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  const mentorCard = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: ${BRAND.lightGray}; border-radius: 12px; padding: 24px;">
      <p style="color: ${BRAND.textMuted}; margin: 0 0 8px 0; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">Your Mentor</p>
      <p style="color: ${BRAND.darkBlue}; margin: 0 0 12px 0; font-size: 20px; font-weight: 700;">${escapeHtml(mentorName)}</p>
      ${mentorBio ? `<p style="color: ${BRAND.textDark}; margin: 0; font-size: 14px; line-height: 1.5;">${escapeHtml(mentorBio)}</p>` : ''}
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(`Great news! A mentor has been assigned to support your project <strong style="color: ${BRAND.darkBlue};">"${escapeHtml(projectName)}"</strong>.`)}
    ${mentorCard}
    ${paragraph('Your mentor will provide guidance, feedback, and support as you develop your ocean protection initiative. They will reach out to you shortly to introduce themselves and schedule your first meeting.')}
    ${infoBox('Mentorship is a valuable opportunity - make the most of their expertise!', 'info')}
  `

  return {
    subject: `A mentor has been assigned to "${projectName}"`,
    html: getEmailWrapper(content),
    text: `
${greeting}

Great news! A mentor has been assigned to support your project "${projectName}".

Your Mentor: ${mentorName}
${mentorBio || ''}

Your mentor will provide guidance, feedback, and support as you develop your ocean protection initiative. They will reach out to you shortly to introduce themselves and schedule your first meeting.

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Not Selected" email template
 */
function getNotSelectedTemplate(
  name: string,
  projectName: string,
  roundName: string,
  feedbackUrl?: string,
  encouragement?: string
): EmailTemplate {
  const greeting = name ? `Dear ${name},` : 'Dear Applicant,'

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(`Thank you for participating in ${escapeHtml(roundName)} with your project <strong>"${escapeHtml(projectName)}"</strong>.`)}
    ${paragraph('After careful consideration by our jury, we regret to inform you that your project was not selected to advance to the next round.')}
    ${infoBox('This decision was incredibly difficult given the high quality of submissions we received this year.', 'info')}
    ${feedbackUrl ? ctaButton(feedbackUrl, 'View Jury Feedback') : ''}
    ${paragraph(encouragement ? escapeHtml(encouragement) : 'We encourage you to continue developing your ocean protection initiative and to apply again in future editions. Your commitment to protecting our oceans is valuable and appreciated.')}
    <p style="color: ${BRAND.textMuted}; margin: 24px 0 0 0; font-size: 14px; text-align: center;">
      Thank you for being part of the Monaco Ocean Protection Challenge community.
    </p>
  `

  return {
    subject: `Update on your application: "${projectName}"`,
    html: getEmailWrapper(content),
    text: `
${greeting}

Thank you for participating in ${roundName} with your project "${projectName}".

After careful consideration by our jury, we regret to inform you that your project was not selected to advance to the next round.

This decision was incredibly difficult given the high quality of submissions we received this year.

${feedbackUrl ? `View jury feedback: ${feedbackUrl}` : ''}

${encouragement || 'We encourage you to continue developing your ocean protection initiative and to apply again in future editions.'}

Thank you for being part of the Monaco Ocean Protection Challenge community.

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Winner Announcement" email template
 */
function getWinnerAnnouncementTemplate(
  name: string,
  projectName: string,
  awardName: string,
  prizeDetails?: string
): EmailTemplate {
  const greeting = name ? `Congratulations ${name}!` : 'Congratulations!'

  const trophyBanner = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background: linear-gradient(135deg, #f59e0b 0%, #eab308 100%); border-radius: 12px; padding: 32px; text-align: center;">
      <p style="color: #ffffff; font-size: 48px; margin: 0 0 12px 0;">&#127942;</p>
      <p style="color: #ffffff; margin: 0 0 8px 0; font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 2px;">Winner</p>
      <h2 style="color: #ffffff; margin: 0; font-size: 24px; font-weight: 700;">${escapeHtml(awardName)}</h2>
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle(greeting)}
    ${trophyBanner}
    ${paragraph(`We are thrilled to announce that your project <strong style="color: ${BRAND.darkBlue};">"${escapeHtml(projectName)}"</strong> has been selected as the winner of the <strong>${escapeHtml(awardName)}</strong>!`)}
    ${infoBox('Your outstanding work in ocean protection has made a lasting impression on our jury.', 'success')}
    ${prizeDetails ? paragraph(`<strong>Your Prize:</strong> ${escapeHtml(prizeDetails)}`) : ''}
    ${paragraph('Our team will be in touch shortly with details about the award ceremony and next steps.')}
  `

  return {
    subject: `You Won! "${projectName}" wins ${awardName}`,
    html: getEmailWrapper(content),
    text: `
${greeting}

We are thrilled to announce that your project "${projectName}" has been selected as the winner of the ${awardName}!

Your outstanding work in ocean protection has made a lasting impression on our jury.

${prizeDetails ? `Your Prize: ${prizeDetails}` : ''}

Our team will be in touch shortly with details about the award ceremony and next steps.

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Assigned to Project" email template (for jury)
 */
function getAssignedToProjectTemplate(
  name: string,
  projectName: string,
  roundName: string,
  deadline?: string,
  assignmentsUrl?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  const projectCard = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: ${BRAND.lightGray}; border-left: 4px solid ${BRAND.teal}; border-radius: 0 12px 12px 0; padding: 20px 24px;">
      <p style="color: ${BRAND.textMuted}; margin: 0 0 4px 0; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">New Assignment</p>
      <p style="color: ${BRAND.darkBlue}; margin: 0; font-size: 18px; font-weight: 700;">${escapeHtml(projectName)}</p>
    </td>
  </tr>
</table>
`

  const deadlineBox = deadline ? `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: #fef2f2; border-left: 4px solid ${BRAND.red}; border-radius: 0 8px 8px 0; padding: 16px 20px;">
      <p style="color: #991b1b; margin: 0 0 4px 0; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">Deadline</p>
      <p style="color: #7f1d1d; margin: 0; font-size: 16px; font-weight: 700;">${escapeHtml(deadline)}</p>
    </td>
  </tr>
</table>
` : ''

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(`You have been assigned a new project to evaluate for <strong style="color: ${BRAND.darkBlue};">${escapeHtml(roundName)}</strong>.`)}
    ${projectCard}
    ${deadlineBox}
    ${paragraph('Please review the project materials and submit your evaluation before the deadline.')}
    ${assignmentsUrl ? ctaButton(assignmentsUrl, 'View Assignment') : ''}
  `

  return {
    subject: `New Assignment: "${projectName}" - ${roundName}`,
    html: getEmailWrapper(content),
    text: `
${greeting}

You have been assigned a new project to evaluate for ${roundName}.

Project: ${projectName}
${deadline ? `Deadline: ${deadline}` : ''}

Please review the project materials and submit your evaluation before the deadline.

${assignmentsUrl ? `View assignment: ${assignmentsUrl}` : ''}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "COI Reassignment" email template (for jury receiving a reassigned project)
 */
function getCOIReassignedTemplate(
  name: string,
  projectName: string,
  roundName: string,
  deadline?: string,
  assignmentsUrl?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  const projectCard = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: #fef3c7; border-left: 4px solid #f59e0b; border-radius: 0 12px 12px 0; padding: 20px 24px;">
      <p style="color: ${BRAND.textMuted}; margin: 0 0 4px 0; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">Reassigned Project</p>
      <p style="color: ${BRAND.darkBlue}; margin: 0; font-size: 18px; font-weight: 700;">${escapeHtml(projectName)}</p>
    </td>
  </tr>
</table>
`

  const deadlineBox = deadline ? `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: #fef2f2; border-left: 4px solid ${BRAND.red}; border-radius: 0 8px 8px 0; padding: 16px 20px;">
      <p style="color: #991b1b; margin: 0 0 4px 0; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">Deadline</p>
      <p style="color: #7f1d1d; margin: 0; font-size: 16px; font-weight: 700;">${escapeHtml(deadline)}</p>
    </td>
  </tr>
</table>
` : ''

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(`A project has been <strong>reassigned to you</strong> for evaluation in <strong style="color: ${BRAND.darkBlue};">${escapeHtml(roundName)}</strong>, because the previously assigned juror declared a conflict of interest.`)}
    ${projectCard}
    ${deadlineBox}
    ${paragraph('Please review the project materials and submit your evaluation before the deadline. This is an additional project on top of your existing assignments.')}
    ${assignmentsUrl ? ctaButton(assignmentsUrl, 'View Assignment') : ''}
  `

  return {
    subject: `Project Reassigned to You: "${projectName}" - ${roundName}`,
    html: getEmailWrapper(content),
    text: `
${greeting}

A project has been reassigned to you for evaluation in ${roundName}, because the previously assigned juror declared a conflict of interest.

Project: ${projectName}
${deadline ? `Deadline: ${deadline}` : ''}

Please review the project materials and submit your evaluation before the deadline. This is an additional project on top of your existing assignments.

${assignmentsUrl ? `View assignment: ${assignmentsUrl}` : ''}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Manual Reassignment" email template (for jury)
 * Sent when an admin manually transfers a project assignment to a juror.
 */
function getManualReassignedTemplate(
  name: string,
  projectNames: string[],
  roundName: string,
  deadline?: string,
  assignmentsUrl?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'
  const count = projectNames.length
  const isSingle = count === 1

  const projectList = projectNames.map((p) => `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 8px 0;">
  <tr>
    <td style="background-color: #eff6ff; border-left: 4px solid ${BRAND.darkBlue}; border-radius: 0 8px 8px 0; padding: 14px 20px;">
      <p style="color: ${BRAND.darkBlue}; margin: 0; font-size: 16px; font-weight: 700;">${escapeHtml(p)}</p>
    </td>
  </tr>
</table>
`).join('')

  const deadlineBox = deadline ? `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: #fef2f2; border-left: 4px solid ${BRAND.red}; border-radius: 0 8px 8px 0; padding: 16px 20px;">
      <p style="color: #991b1b; margin: 0 0 4px 0; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">Deadline</p>
      <p style="color: #7f1d1d; margin: 0; font-size: 16px; font-weight: 700;">${escapeHtml(deadline)}</p>
    </td>
  </tr>
</table>
` : ''

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(`An administrator has <strong>reassigned ${isSingle ? 'a project' : `${count} projects`}</strong> to you for evaluation in <strong style="color: ${BRAND.darkBlue};">${escapeHtml(roundName)}</strong>.`)}
    ${projectList}
    ${deadlineBox}
    ${paragraph(`Please review the project material${isSingle ? '' : 's'} and submit your evaluation${isSingle ? '' : 's'} before the deadline.`)}
    ${assignmentsUrl ? ctaButton(assignmentsUrl, 'View Assignments') : ''}
  `

  const projectListText = projectNames.map((p) => `  - ${p}`).join('\n')

  return {
    subject: `Project${isSingle ? '' : 's'} Reassigned to You - ${roundName}`,
    html: getEmailWrapper(content),
    text: `
${greeting}

An administrator has reassigned ${isSingle ? 'a project' : `${count} projects`} to you for evaluation in ${roundName}.

${isSingle ? `Project: ${projectNames[0]}` : `Projects:\n${projectListText}`}
${deadline ? `Deadline: ${deadline}` : ''}

Please review the project material${isSingle ? '' : 's'} and submit your evaluation${isSingle ? '' : 's'} before the deadline.

${assignmentsUrl ? `View assignments: ${assignmentsUrl}` : ''}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Dropout Reassignment" email template (for jury)
 * Sent when a juror drops out and their projects are redistributed.
 */
function getDropoutReassignedTemplate(
  name: string,
  projectNames: string[],
  roundName: string,
  droppedJurorName: string,
  deadline?: string,
  assignmentsUrl?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'
  const count = projectNames.length
  const isSingle = count === 1

  const projectList = projectNames.map((p) => `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 8px 0;">
  <tr>
    <td style="background-color: #fef3c7; border-left: 4px solid #f59e0b; border-radius: 0 8px 8px 0; padding: 14px 20px;">
      <p style="color: ${BRAND.darkBlue}; margin: 0; font-size: 16px; font-weight: 700;">${escapeHtml(p)}</p>
    </td>
  </tr>
</table>
`).join('')

  const deadlineBox = deadline ? `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: #fef2f2; border-left: 4px solid ${BRAND.red}; border-radius: 0 8px 8px 0; padding: 16px 20px;">
      <p style="color: #991b1b; margin: 0 0 4px 0; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">Deadline</p>
      <p style="color: #7f1d1d; margin: 0; font-size: 16px; font-weight: 700;">${escapeHtml(deadline)}</p>
    </td>
  </tr>
</table>
` : ''

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(`Due to a juror becoming unavailable, ${isSingle ? 'a project has' : `${count} projects have`} been <strong>reassigned to you</strong> for evaluation in <strong style="color: ${BRAND.darkBlue};">${escapeHtml(roundName)}</strong>.`)}
    ${projectList}
    ${deadlineBox}
    ${paragraph(`${isSingle ? 'This project was' : 'These projects were'} previously assigned to ${escapeHtml(droppedJurorName)}, who is no longer available. Please review the project material${isSingle ? '' : 's'} and submit your evaluation${isSingle ? '' : 's'} before the deadline.`)}
    ${assignmentsUrl ? ctaButton(assignmentsUrl, 'View Assignments') : ''}
  `

  const projectListText = projectNames.map((p) => `  - ${p}`).join('\n')

  return {
    subject: `Project${isSingle ? '' : 's'} Reassigned to You (Juror Unavailable) - ${roundName}`,
    html: getEmailWrapper(content),
    text: `
${greeting}

Due to a juror becoming unavailable, ${isSingle ? 'a project has' : `${count} projects have`} been reassigned to you for evaluation in ${roundName}.

${isSingle ? `Project: ${projectNames[0]}` : `Projects:\n${projectListText}`}
${deadline ? `Deadline: ${deadline}` : ''}

${isSingle ? 'This project was' : 'These projects were'} previously assigned to ${droppedJurorName}, who is no longer available. Please review the project material${isSingle ? '' : 's'} and submit your evaluation${isSingle ? '' : 's'} before the deadline.

${assignmentsUrl ? `View assignments: ${assignmentsUrl}` : ''}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Batch Assigned" email template (for jury)
 */
function getBatchAssignedTemplate(
  name: string,
  projectCount: number,
  roundName: string,
  deadline?: string,
  assignmentsUrl?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  const deadlineBox = deadline ? `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: #fef2f2; border-left: 4px solid ${BRAND.red}; border-radius: 0 8px 8px 0; padding: 16px 20px;">
      <p style="color: #991b1b; margin: 0 0 4px 0; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">Deadline</p>
      <p style="color: #7f1d1d; margin: 0; font-size: 16px; font-weight: 700;">${escapeHtml(deadline)}</p>
    </td>
  </tr>
</table>
` : ''

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(`You have been assigned projects to evaluate for <strong style="color: ${BRAND.darkBlue};">${escapeHtml(roundName)}</strong>.`)}
    ${statCard('Projects Assigned', projectCount)}
    ${deadlineBox}
    ${paragraph('Please review each project and submit your evaluations before the deadline. Your expert assessment is crucial to identifying the most promising ocean protection initiatives.')}
    ${assignmentsUrl ? ctaButton(assignmentsUrl, 'View All Assignments') : ''}
  `

  return {
    subject: `${projectCount} Projects Assigned - ${roundName}`,
    html: getEmailWrapper(content),
    text: `
${greeting}

You have been assigned ${projectCount} project${projectCount !== 1 ? 's' : ''} to evaluate for ${roundName}.

${deadline ? `Deadline: ${deadline}` : ''}

Please review each project and submit your evaluations before the deadline.

${assignmentsUrl ? `View assignments: ${assignmentsUrl}` : ''}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Round Now Open" email template (for jury)
 */
function getRoundNowOpenTemplate(
  name: string,
  roundName: string,
  projectCount: number,
  deadline?: string,
  assignmentsUrl?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  const openBanner = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background: linear-gradient(135deg, ${BRAND.teal} 0%, #0891b2 100%); border-radius: 12px; padding: 24px; text-align: center;">
      <p style="color: #ffffff; margin: 0 0 8px 0; font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 2px;">Evaluation Round</p>
      <h2 style="color: #ffffff; margin: 0; font-size: 24px; font-weight: 700;">${escapeHtml(roundName)} is Now Open</h2>
    </td>
  </tr>
</table>
`

  const deadlineBox = deadline ? `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: #fef2f2; border-left: 4px solid ${BRAND.red}; border-radius: 0 8px 8px 0; padding: 16px 20px;">
      <p style="color: #991b1b; margin: 0 0 4px 0; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">Deadline</p>
      <p style="color: #7f1d1d; margin: 0; font-size: 16px; font-weight: 700;">${escapeHtml(deadline)}</p>
    </td>
  </tr>
</table>
` : ''

  const content = `
    ${sectionTitle(greeting)}
    ${openBanner}
    ${statCard('Projects to Evaluate', projectCount)}
    ${deadlineBox}
    ${paragraph('The evaluation round is now open. Please log in to the MOPC Portal to begin reviewing your assigned projects.')}
    ${assignmentsUrl ? ctaButton(assignmentsUrl, 'Start Evaluating') : ''}
  `

  return {
    subject: `${roundName} is Now Open - ${projectCount} Projects Await`,
    html: getEmailWrapper(content),
    text: `
${greeting}

${roundName} is now open for evaluation.

You have ${projectCount} project${projectCount !== 1 ? 's' : ''} to evaluate.
${deadline ? `Deadline: ${deadline}` : ''}

Please log in to the MOPC Portal to begin reviewing your assigned projects.

${assignmentsUrl ? `Start evaluating: ${assignmentsUrl}` : ''}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "24 Hour Reminder" email template (for jury)
 */
function getReminder24HTemplate(
  name: string,
  pendingCount: number,
  roundName: string,
  deadline: string,
  assignmentsUrl?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  const urgentBox = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: #fef3c7; border-left: 4px solid #f59e0b; border-radius: 0 8px 8px 0; padding: 16px 20px;">
      <p style="color: #92400e; margin: 0; font-size: 14px; font-weight: 600;">&#9888; 24 Hours Remaining</p>
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle(greeting)}
    ${urgentBox}
    ${paragraph(`This is a reminder that <strong style="color: ${BRAND.darkBlue};">${escapeHtml(roundName)}</strong> closes in 24 hours.`)}
    ${statCard('Pending Evaluations', pendingCount)}
    ${infoBox(`<strong>Deadline:</strong> ${escapeHtml(deadline)}`, 'warning')}
    ${paragraph('Please complete your remaining evaluations before the deadline to ensure your feedback is included in the selection process.')}
    ${assignmentsUrl ? ctaButton(assignmentsUrl, 'Complete Evaluations') : ''}
  `

  return {
    subject: `Reminder: ${pendingCount} evaluation${pendingCount !== 1 ? 's' : ''} due in 24 hours`,
    html: getEmailWrapper(content),
    text: `
${greeting}

This is a reminder that ${roundName} closes in 24 hours.

You have ${pendingCount} pending evaluation${pendingCount !== 1 ? 's' : ''}.
Deadline: ${deadline}

Please complete your remaining evaluations before the deadline.

${assignmentsUrl ? `Complete evaluations: ${assignmentsUrl}` : ''}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "3 Days Remaining" email template (for jury)
 */
function getReminder3DaysTemplate(
  name: string,
  pendingCount: number,
  roundName: string,
  deadline: string,
  assignmentsUrl?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  const urgentBox = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: #fef3c7; border-left: 4px solid #f59e0b; border-radius: 0 8px 8px 0; padding: 16px 20px;">
      <p style="color: #92400e; margin: 0; font-size: 14px; font-weight: 600;">&#9888; 3 Days Remaining</p>
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle(greeting)}
    ${urgentBox}
    ${paragraph(`This is a reminder that <strong style="color: ${BRAND.darkBlue};">${escapeHtml(roundName)}</strong> closes in 3 days.`)}
    ${statCard('Pending Evaluations', pendingCount)}
    ${infoBox(`<strong>Deadline:</strong> ${escapeHtml(deadline)}`, 'warning')}
    ${paragraph('Please plan to complete your remaining evaluations before the deadline to ensure your feedback is included in the selection process.')}
    ${assignmentsUrl ? ctaButton(assignmentsUrl, 'Complete Evaluations') : ''}
  `

  return {
    subject: `Reminder: ${pendingCount} evaluation${pendingCount !== 1 ? 's' : ''} due in 3 days`,
    html: getEmailWrapper(content),
    text: `
${greeting}

This is a reminder that ${roundName} closes in 3 days.

You have ${pendingCount} pending evaluation${pendingCount !== 1 ? 's' : ''}.
Deadline: ${deadline}

Please plan to complete your remaining evaluations before the deadline.

${assignmentsUrl ? `Complete evaluations: ${assignmentsUrl}` : ''}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "1 Hour Reminder" email template (for jury)
 */
function getReminder1HTemplate(
  name: string,
  pendingCount: number,
  roundName: string,
  deadline: string,
  assignmentsUrl?: string
): EmailTemplate {
  const greeting = name ? `${name},` : 'Attention,'

  const urgentBanner = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background: linear-gradient(135deg, ${BRAND.red} 0%, #dc2626 100%); border-radius: 12px; padding: 24px; text-align: center;">
      <p style="color: #ffffff; margin: 0 0 8px 0; font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 2px;">Urgent</p>
      <h2 style="color: #ffffff; margin: 0; font-size: 24px; font-weight: 700;">1 Hour Remaining</h2>
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle(greeting)}
    ${urgentBanner}
    ${paragraph(`<strong style="color: ${BRAND.red};">${escapeHtml(roundName)}</strong> closes in <strong>1 hour</strong>.`)}
    ${statCard('Evaluations Still Pending', pendingCount)}
    ${paragraph('Please submit your remaining evaluations immediately to ensure they are counted.')}
    ${assignmentsUrl ? ctaButton(assignmentsUrl, 'Submit Now') : ''}
  `

  return {
    subject: `URGENT: ${pendingCount} evaluation${pendingCount !== 1 ? 's' : ''} due in 1 hour`,
    html: getEmailWrapper(content),
    text: `
URGENT

${roundName} closes in 1 hour!

You have ${pendingCount} evaluation${pendingCount !== 1 ? 's' : ''} still pending.

Please submit your remaining evaluations immediately.

${assignmentsUrl ? `Submit now: ${assignmentsUrl}` : ''}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Award Voting Open" email template (for jury)
 */
function getAwardVotingOpenTemplate(
  name: string,
  awardName: string,
  finalistCount: number,
  deadline?: string,
  votingUrl?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  const awardBanner = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%); border-radius: 12px; padding: 24px; text-align: center;">
      <p style="color: #ffffff; font-size: 36px; margin: 0 0 8px 0;">&#127942;</p>
      <p style="color: #ffffff; margin: 0 0 8px 0; font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 2px;">Special Award</p>
      <h2 style="color: #ffffff; margin: 0; font-size: 22px; font-weight: 700;">${escapeHtml(awardName)}</h2>
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle(greeting)}
    ${awardBanner}
    ${paragraph(`Voting is now open for the <strong style="color: ${BRAND.darkBlue};">${escapeHtml(awardName)}</strong>.`)}
    ${statCard('Finalists', finalistCount)}
    ${deadline ? infoBox(`<strong>Voting closes:</strong> ${escapeHtml(deadline)}`, 'warning') : ''}
    ${paragraph('Please review the finalist projects and cast your vote for the most deserving recipient.')}
    ${votingUrl ? ctaButton(votingUrl, 'Cast Your Vote') : ''}
  `

  return {
    subject: `Vote Now: ${awardName}`,
    html: getEmailWrapper(content),
    text: `
${greeting}

Voting is now open for the ${awardName}.

${finalistCount} finalists are competing for this award.
${deadline ? `Voting closes: ${deadline}` : ''}

Please review the finalist projects and cast your vote.

${votingUrl ? `Cast your vote: ${votingUrl}` : ''}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Mentee Assigned" email template (for mentor)
 */
function getMenteeAssignedTemplate(
  name: string,
  projectName: string,
  teamLeadName: string,
  teamLeadEmail?: string,
  projectUrl?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  const projectCard = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: ${BRAND.lightGray}; border-radius: 12px; padding: 24px;">
      <p style="color: ${BRAND.textMuted}; margin: 0 0 8px 0; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">Your New Mentee</p>
      <p style="color: ${BRAND.darkBlue}; margin: 0 0 12px 0; font-size: 20px; font-weight: 700;">${escapeHtml(projectName)}</p>
      <p style="color: ${BRAND.textDark}; margin: 0; font-size: 14px;">
        <strong>Team Lead:</strong> ${escapeHtml(teamLeadName)}${teamLeadEmail ? ` (${escapeHtml(teamLeadEmail)})` : ''}
      </p>
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph('You have been assigned as a mentor to a new project in the Monaco Ocean Protection Challenge.')}
    ${projectCard}
    ${paragraph('As a mentor, you play a crucial role in guiding this team toward success. Please reach out to introduce yourself and schedule your first meeting.')}
    ${infoBox('Your expertise and guidance can make a significant impact on their ocean protection initiative.', 'info')}
    ${projectUrl ? ctaButton(projectUrl, 'View Project Details') : ''}
  `

  return {
    subject: `New Mentee Assignment: "${projectName}"`,
    html: getEmailWrapper(content),
    text: `
${greeting}

You have been assigned as a mentor to a new project in the Monaco Ocean Protection Challenge.

Project: ${projectName}
Team Lead: ${teamLeadName}${teamLeadEmail ? ` (${teamLeadEmail})` : ''}

Please reach out to introduce yourself and schedule your first meeting.

${projectUrl ? `View project: ${projectUrl}` : ''}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Mentee Advanced" email template (for mentor)
 */
function getMenteeAdvancedTemplate(
  name: string,
  projectName: string,
  roundName: string,
  nextRoundName?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  const content = `
    ${sectionTitle(greeting)}
    ${infoBox('Great news about your mentee!', 'success')}
    ${paragraph(`Your mentee project <strong style="color: ${BRAND.darkBlue};">"${escapeHtml(projectName)}"</strong> has advanced to the next stage!`)}
    ${statCard('Advanced From', roundName)}
    ${nextRoundName ? paragraph(`They will now compete in <strong>${escapeHtml(nextRoundName)}</strong>.`) : ''}
    ${paragraph('Your guidance is making a difference. Continue supporting the team as they progress in the competition.')}
  `

  return {
    subject: `Your Mentee Advanced: "${projectName}"`,
    html: getEmailWrapper(content),
    text: `
${greeting}

Great news! Your mentee project "${projectName}" has advanced to the next stage.

Advanced from: ${roundName}
${nextRoundName ? `Now competing in: ${nextRoundName}` : ''}

Your guidance is making a difference. Continue supporting the team as they progress.

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Mentee Won" email template (for mentor)
 */
function getMenteeWonTemplate(
  name: string,
  projectName: string,
  awardName: string
): EmailTemplate {
  const greeting = name ? `Congratulations ${name}!` : 'Congratulations!'

  const trophyBanner = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background: linear-gradient(135deg, #f59e0b 0%, #eab308 100%); border-radius: 12px; padding: 24px; text-align: center;">
      <p style="color: #ffffff; font-size: 48px; margin: 0 0 12px 0;">&#127942;</p>
      <p style="color: #ffffff; margin: 0; font-size: 16px; font-weight: 600;">Your Mentee Won!</p>
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle(greeting)}
    ${trophyBanner}
    ${paragraph(`Your mentee project <strong style="color: ${BRAND.darkBlue};">"${escapeHtml(projectName)}"</strong> has won the <strong>${escapeHtml(awardName)}</strong>!`)}
    ${infoBox('Your mentorship played a vital role in their success.', 'success')}
    ${paragraph('Thank you for your dedication and support. The impact of your guidance extends beyond this competition.')}
  `

  return {
    subject: `Your Mentee Won: "${projectName}" - ${awardName}`,
    html: getEmailWrapper(content),
    text: `
${greeting}

Your mentee project "${projectName}" has won the ${awardName}!

Your mentorship played a vital role in their success.

Thank you for your dedication and support.

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "New Application" email template (for admins)
 */
function getNewApplicationTemplate(
  projectName: string,
  applicantName: string,
  applicantEmail: string,
  programName: string,
  reviewUrl?: string
): EmailTemplate {
  const applicationCard = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background-color: ${BRAND.lightGray}; border-left: 4px solid ${BRAND.teal}; border-radius: 0 12px 12px 0; padding: 20px 24px;">
      <p style="color: ${BRAND.textMuted}; margin: 0 0 4px 0; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px;">New Application</p>
      <p style="color: ${BRAND.darkBlue}; margin: 0 0 12px 0; font-size: 18px; font-weight: 700;">${escapeHtml(projectName)}</p>
      <p style="color: ${BRAND.textDark}; margin: 0; font-size: 14px;">
        <strong>Applicant:</strong> ${escapeHtml(applicantName)} (${escapeHtml(applicantEmail)})
      </p>
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle('New Application Received')}
    ${paragraph(`A new application has been submitted to <strong style="color: ${BRAND.darkBlue};">${escapeHtml(programName)}</strong>.`)}
    ${applicationCard}
    ${reviewUrl ? ctaButton(reviewUrl, 'Review Application') : ''}
  `

  return {
    subject: `New Application: "${projectName}"`,
    html: getEmailWrapper(content),
    text: `
New Application Received

A new application has been submitted to ${programName}.

Project: ${projectName}
Applicant: ${applicantName} (${applicantEmail})

${reviewUrl ? `Review application: ${reviewUrl}` : ''}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Project Advanced" notification email template
 */
export function getAdvancementNotificationTemplate(
  name: string,
  projectName: string,
  fromRoundName: string,
  toRoundName: string,
  customMessage?: string,
  accountUrl?: string,
  fullCustomBody?: boolean,
): EmailTemplate {
  const greeting = name ? `Congratulations ${name}!` : 'Congratulations!'

  const escapedMessage = customMessage
    ? escapeHtml(customMessage).replace(/\n/g, '<br>')
    : null

  // Full custom body mode: only the custom message inside the branded wrapper
  if (fullCustomBody && escapedMessage) {
    const content = `
      ${sectionTitle(greeting)}
      <div style="color: ${BRAND.textDark}; font-size: 15px; line-height: 1.7; margin: 20px 0;">${escapedMessage}</div>
      ${accountUrl
        ? ctaButton(accountUrl, 'Create Your Account')
        : ctaButton('/applicant', 'View Your Dashboard')}
    `
    return {
      subject: `Your project has advanced: "${projectName}"`,
      html: getEmailWrapper(content),
      text: `${greeting}\n\n${customMessage}\n\n${accountUrl ? `Create your account: ${getBaseUrl()}${accountUrl}` : `Visit your dashboard: ${getBaseUrl()}/applicant`}\n\n---\nMonaco Ocean Protection Challenge\nTogether for a healthier ocean.`,
    }
  }

  const celebrationBanner = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background: linear-gradient(135deg, #059669 0%, #0d9488 100%); border-radius: 12px; padding: 24px; text-align: center;">
      <p style="color: #ffffff; margin: 0 0 8px 0; font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 2px;">Great News</p>
      <h2 style="color: #ffffff; margin: 0; font-size: 28px; font-weight: 700;">Your project has advanced!</h2>
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle(greeting)}
    ${celebrationBanner}
    ${infoBox(`<strong>"${escapeHtml(projectName)}"</strong>`, 'success')}
    ${infoBox(`Advanced from <strong>${escapeHtml(fromRoundName)}</strong> to <strong>${escapeHtml(toRoundName)}</strong>`, 'info')}
    ${
      escapedMessage
        ? `<div style="background-color: #f5f5f5; border-radius: 8px; padding: 20px; margin: 20px 0; color: ${BRAND.textDark}; font-size: 15px; line-height: 1.7;">${escapedMessage}</div>`
        : paragraph('Our team will be in touch with more details about the next phase.')
    }
    ${accountUrl
      ? ctaButton(accountUrl, 'Create Your Account')
      : ctaButton('/applicant', 'View Your Dashboard')}
  `

  return {
    subject: `Your project has advanced: "${projectName}"`,
    html: getEmailWrapper(content),
    text: `
${greeting}

Your project has advanced!

Project: ${projectName}
Advanced from: ${fromRoundName}
To: ${toRoundName}

${customMessage || 'Our team will be in touch with more details about the next phase.'}

${accountUrl
  ? `Create your account: ${getBaseUrl()}${accountUrl}`
  : `Visit your dashboard: ${getBaseUrl()}/applicant`}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Project Not Advanced" (rejection) notification email template
 */
export function getRejectionNotificationTemplate(
  name: string,
  projectName: string,
  roundName: string,
  customMessage?: string,
  fullCustomBody?: boolean,
): EmailTemplate {
  const greeting = name ? `Dear ${name},` : 'Dear Applicant,'

  const escapedMessage = customMessage
    ? escapeHtml(customMessage).replace(/\n/g, '<br>')
    : null

  // Full custom body mode: only the custom message inside the branded wrapper
  if (fullCustomBody && escapedMessage) {
    const content = `
      ${sectionTitle(greeting)}
      <div style="color: ${BRAND.textDark}; font-size: 15px; line-height: 1.7; margin: 20px 0;">${escapedMessage}</div>
      <p style="color: ${BRAND.textMuted}; margin: 24px 0 0 0; font-size: 14px; text-align: center;">
        Thank you for being part of the Monaco Ocean Protection Challenge community.
      </p>
    `
    return {
      subject: `Update on your application: "${projectName}"`,
      html: getEmailWrapper(content),
      text: `${greeting}\n\n${customMessage}\n\nThank you for being part of the Monaco Ocean Protection Challenge community.\n\n---\nMonaco Ocean Protection Challenge\nTogether for a healthier ocean.`,
    }
  }

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(`Thank you for your participation in <strong>${escapeHtml(roundName)}</strong> with your project <strong>"${escapeHtml(projectName)}"</strong>.`)}
    ${infoBox('After careful review by our jury, we regret to inform you that your project was not selected to advance at this stage.', 'info')}
    ${
      escapedMessage
        ? `<div style="background-color: #f5f5f5; border-radius: 8px; padding: 20px; margin: 20px 0; color: ${BRAND.textDark}; font-size: 15px; line-height: 1.7;">${escapedMessage}</div>`
        : ''
    }
    ${paragraph('We encourage you to continue developing your ocean protection initiative and to apply again in future editions. Your commitment to protecting our oceans is valuable and appreciated.')}
    <p style="color: ${BRAND.textMuted}; margin: 24px 0 0 0; font-size: 14px; text-align: center;">
      Thank you for being part of the Monaco Ocean Protection Challenge community.
    </p>
  `

  return {
    subject: `Update on your application: "${projectName}"`,
    html: getEmailWrapper(content),
    text: `
${greeting}

Thank you for your participation in ${roundName} with your project "${projectName}".

After careful review by our jury, we regret to inform you that your project was not selected to advance at this stage.

${customMessage || ''}

We encourage you to continue developing your ocean protection initiative and to apply again in future editions.

Thank you for being part of the Monaco Ocean Protection Challenge community.

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Award Winner" notification email template — used when finalizing
 * the terminal round of a special award (no further rounds to advance to).
 */
export function getAwardWinnerNotificationTemplate(
  name: string,
  projectName: string,
  winnerLabel: string,
  customMessage?: string,
  accountUrl?: string,
  fullCustomBody?: boolean,
): EmailTemplate {
  const greeting = name ? `Congratulations ${name}!` : 'Congratulations!'

  const escapedMessage = customMessage
    ? escapeHtml(customMessage).replace(/\n/g, '<br>')
    : null

  if (fullCustomBody && escapedMessage) {
    const content = `
      ${sectionTitle(greeting)}
      <div style="color: ${BRAND.textDark}; font-size: 15px; line-height: 1.7; margin: 20px 0;">${escapedMessage}</div>
      ${accountUrl ? ctaButton(accountUrl, 'Create Your Account') : ctaButton('/applicant', 'View Your Dashboard')}
    `
    return {
      subject: `Your project has won: "${projectName}"`,
      html: getEmailWrapper(content),
      text: `${greeting}\n\n${customMessage}\n\n${accountUrl ? `Create your account: ${getBaseUrl()}${accountUrl}` : `Visit your dashboard: ${getBaseUrl()}/applicant`}\n\n---\nMonaco Ocean Protection Challenge\nTogether for a healthier ocean.`,
    }
  }

  const winnerBanner = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background: linear-gradient(135deg, #b45309 0%, #f59e0b 100%); border-radius: 12px; padding: 28px; text-align: center;">
      <p style="color: #ffffff; margin: 0 0 8px 0; font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 2px;">Winner Announcement</p>
      <h2 style="color: #ffffff; margin: 0; font-size: 28px; font-weight: 700;">Your project has won!</h2>
    </td>
  </tr>
</table>
`

  const content = `
    ${sectionTitle(greeting)}
    ${winnerBanner}
    ${infoBox(`<strong>"${escapeHtml(projectName)}"</strong> has been selected as a winner of <strong>${escapeHtml(winnerLabel)}</strong>.`, 'success')}
    ${
      escapedMessage
        ? `<div style="background-color: #f5f5f5; border-radius: 8px; padding: 20px; margin: 20px 0; color: ${BRAND.textDark}; font-size: 15px; line-height: 1.7;">${escapedMessage}</div>`
        : paragraph('Our team will reach out shortly with details on the next steps, including award presentation, communications, and any administrative requirements.')
    }
    ${accountUrl ? ctaButton(accountUrl, 'Create Your Account') : ctaButton('/applicant', 'View Your Dashboard')}
  `

  return {
    subject: `Your project has won: "${projectName}"`,
    html: getEmailWrapper(content),
    text: `
${greeting}

Your project has won!

Project: ${projectName}
${winnerLabel}

"${projectName}" has been selected as a winner of ${winnerLabel}.

${customMessage || 'Our team will reach out shortly with details on the next steps, including award presentation, communications, and any administrative requirements.'}

${accountUrl ? `Create your account: ${getBaseUrl()}${accountUrl}` : `Visit your dashboard: ${getBaseUrl()}/applicant`}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate "Under Consideration for Special Award" notification email template
 */
export function getAwardSelectionNotificationTemplate(
  name: string,
  projectName: string,
  awardName: string,
  customMessage?: string,
  accountUrl?: string,
): EmailTemplate {
  const greeting = name ? `Dear ${name},` : 'Dear Applicant,'

  const announcementBanner = `
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin: 20px 0;">
  <tr>
    <td style="background: linear-gradient(135deg, ${BRAND.darkBlue} 0%, ${BRAND.teal} 100%); border-radius: 12px; padding: 24px; text-align: center;">
      <p style="color: #ffffff; margin: 0 0 8px 0; font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 2px;">Special Award Consideration</p>
      <h2 style="color: #ffffff; margin: 0; font-size: 24px; font-weight: 700;">Your project is under consideration</h2>
    </td>
  </tr>
</table>
`

  const escapedMessage = customMessage
    ? escapeHtml(customMessage).replace(/\n/g, '<br>')
    : null

  const content = `
    ${sectionTitle(greeting)}
    ${announcementBanner}
    ${infoBox(`<strong>"${escapeHtml(projectName)}"</strong> has been shortlisted for consideration for the <strong>${escapeHtml(awardName)}</strong>.`, 'info')}
    ${paragraph('This means your project has caught the attention of our selection committee and is being evaluated for this special recognition. Please note that this is not a final award — further review and evaluation steps may follow.')}
    ${
      escapedMessage
        ? `<div style="background-color: #f5f5f5; border-radius: 8px; padding: 20px; margin: 20px 0; color: ${BRAND.textDark}; font-size: 15px; line-height: 1.7;">${escapedMessage}</div>`
        : paragraph('Our team will be in touch with more details about this award and next steps.')
    }
    ${accountUrl
      ? ctaButton(accountUrl, 'Create Your Account')
      : ctaButton('/applicant', 'View Your Dashboard')}
  `

  return {
    subject: `Your project is under consideration for ${awardName}: "${projectName}"`,
    html: getEmailWrapper(content),
    text: `
${greeting}

Your project is under consideration for a special award.

Project: ${projectName}
Award: ${awardName}

Your project has been shortlisted for consideration for the ${awardName}. This means your project has caught the attention of our selection committee and is being evaluated for this special recognition. Please note that this is not a final award — further review and evaluation steps may follow.

${customMessage || 'Our team will be in touch with more details about this award and next steps.'}

${accountUrl
  ? `Create your account: ${getBaseUrl()}${accountUrl}`
  : `Visit your dashboard: ${getBaseUrl()}/applicant`}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Generate a preview HTML wrapper for admin email previews
 */
export function getEmailPreviewHtml(subject: string, body: string): string {
  const formattedBody = escapeHtml(body).replace(/\n/g, '<br>')
  const content = `
    ${sectionTitle('Hello [Name],')}
    <div style="color: ${BRAND.textDark}; font-size: 15px; line-height: 1.7; margin: 20px 0;">
      ${formattedBody}
    </div>
    ${ctaButton('#', 'View Details')}
    <p style="color: ${BRAND.textMuted}; margin: 24px 0 0 0; font-size: 13px; text-align: center;">
      You received this email because of your notification preferences on the MOPC Portal.
    </p>
  `
  return getEmailWrapper(content)
}

/**
 * Generate "Account Setup Reminder" email template
 * Sent to semi-finalist team members who haven't set up their account yet.
 */
export function getAccountReminderTemplate(
  name: string,
  projectName: string,
  accountUrl: string,
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  const content = `
    ${sectionTitle(greeting)}
    ${paragraph(`Your project <strong>"${escapeHtml(projectName)}"</strong> has been selected as a semi-finalist in the Monaco Ocean Protection Challenge.`)}
    ${infoBox('Please set up your account to access your applicant dashboard and stay up to date with the competition.', 'warning')}
    ${ctaButton(accountUrl, 'Set Up Your Account')}
    ${paragraph('If you have any questions, please contact the MOPC team.')}
  `

  return {
    subject: `Action Required: Set up your MOPC account — "${projectName}"`,
    html: getEmailWrapper(content),
    text: `${greeting}\n\nYour project "${projectName}" has been selected as a semi-finalist in the Monaco Ocean Protection Challenge.\n\nPlease set up your account to access your applicant dashboard.\n\nSet up your account: ${getBaseUrl()}${accountUrl}\n\nIf you have any questions, please contact the MOPC team.\n\n---\nMonaco Ocean Protection Challenge\nTogether for a healthier ocean.`,
  }
}

// =============================================================================
// Logistics email templates
// =============================================================================

/**
 * Reminder email sent to a team lead when the confirmation deadline is approaching.
 */
function getFinalistReminderTemplate(
  name: string,
  projectTitle: string,
  deadline: Date,
  confirmUrl: string,
): EmailTemplate {
  const greeting = name ? `Hi ${name},` : 'Hi there,'
  const formattedDeadline = deadline.toLocaleString('en-GB', {
    timeZone: 'Europe/Paris',
    dateStyle: 'full',
    timeStyle: 'short',
  })

  const content = `
    ${sectionTitle('Reminder: Grand-Finale Attendance')}
    ${paragraph(greeting)}
    ${paragraph(`Your project <strong>${escapeHtml(projectTitle)}</strong> has been selected as a finalist for the Monaco Ocean Protection Challenge Grand Finale. Your confirmation is still pending.`)}
    ${infoBox(`Please confirm your attendance <strong>by ${escapeHtml(formattedDeadline)} (Paris time)</strong>. If no response is received by the deadline, your slot may be reallocated.`, 'warning')}
    ${ctaButton(confirmUrl, 'Confirm attendance')}
    ${paragraph('If you have any questions, please reach out to the MOPC team.')}
  `

  const text = [
    greeting,
    '',
    `Your project "${projectTitle}" has been selected as a finalist for the Monaco Ocean Protection Challenge Grand Finale. Your confirmation is still pending.`,
    '',
    `Please confirm your attendance by ${formattedDeadline} (Paris time). If no response is received by the deadline, your slot may be reallocated.`,
    '',
    `Confirm attendance: ${confirmUrl}`,
    '',
    'If you have any questions, please reach out to the MOPC team.',
    '',
    'The MOPC team',
  ].join('\n')

  return {
    subject: 'Reminder: confirm your grand-finale attendance',
    html: getEmailWrapper(content),
    text,
  }
}

/**
 * Reminder email sent to a finalist team to upload their Grand Final documents.
 */
function getGrandFinalDocsReminderTemplate(
  name: string,
  projectTitle: string,
  deadline: Date | null,
  uploadUrl: string,
  missing: string[],
): EmailTemplate {
  const greeting = name ? `Hi ${name},` : 'Hi there,'
  const formattedDeadline = deadline
    ? deadline.toLocaleString('en-GB', { timeZone: 'Europe/Paris', dateStyle: 'full', timeStyle: 'short' })
    : null
  const missingLine = missing.length
    ? `Still needed: <strong>${escapeHtml(missing.join(', '))}</strong>.`
    : 'Please make sure all required documents are uploaded.'
  const content = `
    ${sectionTitle('Grand Final — Final Documents')}
    ${paragraph(greeting)}
    ${paragraph(`Please upload the final documents for <strong>${escapeHtml(projectTitle)}</strong> ahead of the Monaco Ocean Protection Challenge Grand Finale.`)}
    ${paragraph(missingLine)}
    ${formattedDeadline ? infoBox(`Deadline: <strong>${escapeHtml(formattedDeadline)} (Paris time)</strong>.`, 'warning') : ''}
    ${ctaButton(uploadUrl, 'Upload documents')}
    ${paragraph('If you have any questions, please reach out to the MOPC team.')}
  `
  const text = [
    greeting, '',
    `Please upload the final documents for "${projectTitle}" ahead of the Grand Finale.`,
    missing.length ? `Still needed: ${missing.join(', ')}.` : 'Please make sure all required documents are uploaded.',
    formattedDeadline ? `Deadline: ${formattedDeadline} (Paris time).` : '',
    `Upload documents: ${uploadUrl}`, '', 'The MOPC team',
  ].join('\n')
  return { subject: 'Action needed: upload your Grand Final documents', html: getEmailWrapper(content), text }
}

/**
 * Notification email sent to a team when their confirmed finalist slot is withdrawn by an admin.
 */
function getFinalistWithdrawnTemplate(
  name: string,
  projectTitle: string,
  reason?: string,
): EmailTemplate {
  const greeting = name ? `Hi ${name},` : 'Hi there,'

  const reasonHtml = reason
    ? paragraph(`<strong>Reason:</strong> ${escapeHtml(reason)}`)
    : ''
  const reasonText = reason ? `Reason: ${reason}\n\n` : ''

  const content = `
    ${sectionTitle('Grand-Finale Slot Withdrawn')}
    ${paragraph(greeting)}
    ${infoBox(`We regret to inform you that your team's confirmed spot at the Grand Finale has been withdrawn for the project <strong>${escapeHtml(projectTitle)}</strong>.`, 'warning')}
    ${reasonHtml}
    ${paragraph('If you believe this is an error or have questions, please contact the MOPC team as soon as possible.')}
  `

  const text = [
    greeting,
    '',
    `We regret to inform you that your team's confirmed spot at the Grand Finale has been withdrawn for the project "${projectTitle}".`,
    '',
    reasonText + 'If you believe this is an error or have questions, please contact the MOPC team as soon as possible.',
    '',
    'The MOPC team',
  ].join('\n')

  return {
    subject: 'Your grand-finale slot has been withdrawn',
    html: getEmailWrapper(content),
    text,
  }
}

/**
 * Travel confirmation email for a grand-finale attendee, including flight and hotel details.
 */
function getTravelConfirmedTemplate(
  name: string,
  projectTitle: string,
  flight: {
    arrivalAt?: Date | string | null
    arrivalFlightNumber?: string | null
    arrivalAirport?: string | null
    departureAt?: Date | string | null
    departureFlightNumber?: string | null
    departureAirport?: string | null
  },
  hotel?: {
    name: string
    address?: string | null
    link?: string | null
  },
  room?: {
    roomNumber?: string | null
    checkInAt?: string | null
    checkOutAt?: string | null
  },
): EmailTemplate {
  const greeting = name ? `Hi ${name},` : 'Hi there,'

  const fmtDate = (d: Date | string | null | undefined) => {
    if (!d) return null
    const dt = d instanceof Date ? d : new Date(d)
    return dt.toLocaleString('en-GB', { timeZone: 'Europe/Paris', dateStyle: 'full', timeStyle: 'short' })
  }

  const arrivalLines: string[] = []
  const departureLines: string[] = []

  if (flight.arrivalAt) arrivalLines.push(`Date: ${fmtDate(flight.arrivalAt)} (Paris time)`)
  if (flight.arrivalFlightNumber) arrivalLines.push(`Flight: ${flight.arrivalFlightNumber}`)
  if (flight.arrivalAirport) arrivalLines.push(`Airport: ${flight.arrivalAirport}`)

  if (flight.departureAt) departureLines.push(`Date: ${fmtDate(flight.departureAt)} (Paris time)`)
  if (flight.departureFlightNumber) departureLines.push(`Flight: ${flight.departureFlightNumber}`)
  if (flight.departureAirport) departureLines.push(`Airport: ${flight.departureAirport}`)

  const arrivalHtml =
    arrivalLines.length > 0
      ? `<h3 style="margin:20px 0 8px;color:#0f172a;font-size:14px;font-weight:600;text-transform:uppercase;letter-spacing:1px;">Arrival</h3>` +
        `<ul style="margin:0 0 16px;padding-left:20px;color:${BRAND.textDark};font-size:14px;">` +
        arrivalLines.map((l) => `<li style="margin:4px 0;">${escapeHtml(l)}</li>`).join('') +
        `</ul>`
      : ''

  const departureHtml =
    departureLines.length > 0
      ? `<h3 style="margin:20px 0 8px;color:#0f172a;font-size:14px;font-weight:600;text-transform:uppercase;letter-spacing:1px;">Departure</h3>` +
        `<ul style="margin:0 0 16px;padding-left:20px;color:${BRAND.textDark};font-size:14px;">` +
        departureLines.map((l) => `<li style="margin:4px 0;">${escapeHtml(l)}</li>`).join('') +
        `</ul>`
      : ''

  const fmtDateShort = (d: string | null | undefined) => {
    if (!d) return null
    const dt = new Date(d)
    return dt.toLocaleString('en-GB', { timeZone: 'Europe/Paris', dateStyle: 'long', timeStyle: 'short' })
  }

  const roomLines: string[] = []
  if (room?.roomNumber) roomLines.push(`Room: ${room.roomNumber}`)
  if (room?.checkInAt) roomLines.push(`Check-in: ${fmtDateShort(room.checkInAt)} (Paris time)`)
  if (room?.checkOutAt) roomLines.push(`Check-out: ${fmtDateShort(room.checkOutAt)} (Paris time)`)

  const roomHtml =
    roomLines.length > 0
      ? `<ul style="margin:8px 0 0;padding-left:20px;color:${BRAND.textDark};font-size:14px;">` +
        roomLines.map((l) => `<li style="margin:4px 0;">${escapeHtml(l)}</li>`).join('') +
        `</ul>`
      : ''

  const hotelHtml = hotel
    ? `<h3 style="margin:20px 0 8px;color:#0f172a;font-size:14px;font-weight:600;text-transform:uppercase;letter-spacing:1px;">Hotel</h3>` +
      infoBox(
        `<strong>${escapeHtml(hotel.name)}</strong>` +
          (hotel.address ? `<br>${escapeHtml(hotel.address)}` : '') +
          (hotel.link ? `<br><a href="${hotel.link}" style="color:${BRAND.darkBlue};">View hotel</a>` : '') +
          roomHtml,
        'info',
      )
    : ''

  const roomTextLines = roomLines.length > 0 ? '\n' + roomLines.map((l) => `  ${l}`).join('\n') : ''
  const hotelText = hotel
    ? ['\nHotel:', `  ${hotel.name}`, ...(hotel.address ? [`  ${hotel.address}`] : []), ...(hotel.link ? [`  ${hotel.link}`] : []), roomTextLines].join('\n')
    : ''

  const content = `
    ${sectionTitle('Your travel is confirmed!')}
    ${paragraph(greeting)}
    ${paragraph(`Great news — your travel arrangements for the Grand Finale (<strong>${escapeHtml(projectTitle)}</strong>) have been confirmed. Here are your details:`)}
    ${arrivalHtml}
    ${departureHtml}
    ${hotelHtml}
    ${paragraph('If anything looks incorrect, please contact the MOPC team immediately.')}
  `

  const arrivalText = arrivalLines.length > 0 ? '\nArrival:\n' + arrivalLines.map((l) => `  ${l}`).join('\n') : ''
  const departureText = departureLines.length > 0 ? '\nDeparture:\n' + departureLines.map((l) => `  ${l}`).join('\n') : ''

  const text = [
    greeting,
    '',
    `Great news — your travel arrangements for the Grand Finale ("${projectTitle}") have been confirmed. Here are your details:`,
    arrivalText,
    departureText,
    hotelText,
    '',
    'If anything looks incorrect, please contact the MOPC team immediately.',
    '',
    'The MOPC team',
  ].join('\n')

  return {
    subject: 'Your grand-finale travel is confirmed',
    html: getEmailWrapper(content),
    text,
  }
}

/**
 * Visa status update email for a grand-finale attendee.
 */
function getVisaStatusTemplate(
  name: string,
  projectTitle: string,
  status: 'INVITATION_SENT' | 'APPOINTMENT_BOOKED' | 'GRANTED' | 'DENIED',
  note?: string,
): EmailTemplate {
  const greeting = name ? `Hi ${name},` : 'Hi there,'

  const statusCopy: Record<typeof status, { headline: string; body: string; variant: 'info' | 'success' | 'warning' }> = {
    INVITATION_SENT: {
      headline: 'Visa invitation letter sent',
      body: 'Your official visa invitation letter for the Grand Finale has been sent. Please use it when applying for your visa at the relevant consulate or embassy.',
      variant: 'info',
    },
    APPOINTMENT_BOOKED: {
      headline: 'Visa appointment booked',
      body: 'A visa appointment has been booked on your behalf. Please check your inbox or contact the MOPC team for the appointment details.',
      variant: 'info',
    },
    GRANTED: {
      headline: 'Visa granted — see you in Monaco!',
      body: 'Congratulations — your visa has been granted. We look forward to welcoming you to the Monaco Ocean Protection Challenge Grand Finale.',
      variant: 'success',
    },
    DENIED: {
      headline: 'Visa application outcome',
      body: 'Unfortunately, your visa application has not been successful at this time. Please contact the MOPC team as soon as possible so we can discuss next steps.',
      variant: 'warning',
    },
  }

  const { headline, body, variant } = statusCopy[status]
  const noteHtml = note ? paragraph(`<em>${escapeHtml(note)}</em>`) : ''
  const noteText = note ? `\n${note}\n` : ''

  const content = `
    ${sectionTitle('Visa update for the Grand Finale')}
    ${paragraph(greeting)}
    ${paragraph(`This is an update regarding your visa for the Grand Finale — project <strong>${escapeHtml(projectTitle)}</strong>.`)}
    ${infoBox(`<strong>${escapeHtml(headline)}</strong><br>${escapeHtml(body)}`, variant)}
    ${noteHtml}
    ${paragraph('If you have any questions, please don\'t hesitate to contact the MOPC team.')}
  `

  const text = [
    greeting,
    '',
    `This is an update regarding your visa for the Grand Finale — project "${projectTitle}".`,
    '',
    `${headline}`,
    body,
    noteText,
    'If you have any questions, please don\'t hesitate to contact the MOPC team.',
    '',
    'The MOPC team',
  ].join('\n')

  return {
    subject: 'Visa update for the grand finale',
    html: getEmailWrapper(content),
    text,
  }
}

/**
 * Template registry mapping notification types to template generators
 */
type TemplateGenerator = (context: NotificationEmailContext) => EmailTemplate

export const NOTIFICATION_EMAIL_TEMPLATES: Record<string, TemplateGenerator> = {
  // Team/Applicant templates
  ADVANCED_SEMIFINAL: (ctx) =>
    getAdvancedSemifinalTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Your Project',
      (ctx.metadata?.programName as string) || 'MOPC',
      ctx.metadata?.nextSteps as string | undefined
    ),
  ADVANCED_FINAL: (ctx) =>
    getAdvancedFinalTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Your Project',
      (ctx.metadata?.programName as string) || 'MOPC',
      ctx.metadata?.nextSteps as string | undefined
    ),
  MENTOR_ASSIGNED: (ctx) =>
    getMentorAssignedTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Your Project',
      (ctx.metadata?.mentorName as string) || 'Your Mentor',
      ctx.metadata?.mentorBio as string | undefined
    ),
  NOT_SELECTED: (ctx) =>
    getNotSelectedTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Your Project',
      (ctx.metadata?.roundName as string) || 'this round',
      ctx.linkUrl,
      ctx.metadata?.encouragement as string | undefined
    ),
  WINNER_ANNOUNCEMENT: (ctx) =>
    getWinnerAnnouncementTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Your Project',
      (ctx.metadata?.awardName as string) || 'the Award',
      ctx.metadata?.prizeDetails as string | undefined
    ),

  // Jury templates
  ASSIGNED_TO_PROJECT: (ctx) =>
    getAssignedToProjectTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Project',
      (ctx.metadata?.roundName as string) || 'this round',
      ctx.metadata?.deadline as string | undefined,
      ctx.linkUrl
    ),
  COI_REASSIGNED: (ctx) =>
    getCOIReassignedTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Project',
      (ctx.metadata?.roundName as string) || 'this round',
      ctx.metadata?.deadline as string | undefined,
      ctx.linkUrl
    ),
  MANUAL_REASSIGNED: (ctx) =>
    getManualReassignedTemplate(
      ctx.name || '',
      (ctx.metadata?.projectNames as string[]) || [(ctx.metadata?.projectName as string) || 'Project'],
      (ctx.metadata?.roundName as string) || 'this round',
      ctx.metadata?.deadline as string | undefined,
      ctx.linkUrl
    ),
  DROPOUT_REASSIGNED: (ctx) =>
    getDropoutReassignedTemplate(
      ctx.name || '',
      (ctx.metadata?.projectNames as string[]) || [(ctx.metadata?.projectName as string) || 'Project'],
      (ctx.metadata?.roundName as string) || 'this round',
      (ctx.metadata?.droppedJurorName as string) || 'a fellow juror',
      ctx.metadata?.deadline as string | undefined,
      ctx.linkUrl
    ),
  BATCH_ASSIGNED: (ctx) =>
    getBatchAssignedTemplate(
      ctx.name || '',
      (ctx.metadata?.projectCount as number) || 1,
      (ctx.metadata?.roundName as string) || 'this round',
      ctx.metadata?.deadline as string | undefined,
      ctx.linkUrl
    ),
  ROUND_NOW_OPEN: (ctx) =>
    getRoundNowOpenTemplate(
      ctx.name || '',
      (ctx.metadata?.roundName as string) || 'Evaluation Round',
      (ctx.metadata?.projectCount as number) || 0,
      ctx.metadata?.deadline as string | undefined,
      ctx.linkUrl
    ),
  REMINDER_3_DAYS: (ctx) =>
    getReminder3DaysTemplate(
      ctx.name || '',
      (ctx.metadata?.pendingCount as number) || 0,
      (ctx.metadata?.roundName as string) || 'this round',
      (ctx.metadata?.deadline as string) || 'Soon',
      ctx.linkUrl
    ),
  REMINDER_24H: (ctx) =>
    getReminder24HTemplate(
      ctx.name || '',
      (ctx.metadata?.pendingCount as number) || 0,
      (ctx.metadata?.roundName as string) || 'this round',
      (ctx.metadata?.deadline as string) || 'Soon',
      ctx.linkUrl
    ),
  REMINDER_1H: (ctx) =>
    getReminder1HTemplate(
      ctx.name || '',
      (ctx.metadata?.pendingCount as number) || 0,
      (ctx.metadata?.roundName as string) || 'this round',
      (ctx.metadata?.deadline as string) || 'Very Soon',
      ctx.linkUrl
    ),
  AWARD_VOTING_OPEN: (ctx) =>
    getAwardVotingOpenTemplate(
      ctx.name || '',
      (ctx.metadata?.awardName as string) || 'Special Award',
      (ctx.metadata?.finalistCount as number) || 0,
      ctx.metadata?.deadline as string | undefined,
      ctx.linkUrl
    ),

  // Mentor templates
  MENTEE_ASSIGNED: (ctx) =>
    getMenteeAssignedTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Project',
      (ctx.metadata?.teamLeadName as string) || 'Team Lead',
      ctx.metadata?.teamLeadEmail as string | undefined,
      ctx.linkUrl
    ),
  MENTEE_ADVANCED: (ctx) =>
    getMenteeAdvancedTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Project',
      (ctx.metadata?.roundName as string) || 'this round',
      ctx.metadata?.nextRoundName as string | undefined
    ),
  MENTEE_WON: (ctx) =>
    getMenteeWonTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Project',
      (ctx.metadata?.awardName as string) || 'Award'
    ),

  ADVANCEMENT_NOTIFICATION: (ctx) =>
    getAdvancementNotificationTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Your Project',
      (ctx.metadata?.fromRoundName as string) || 'previous round',
      (ctx.metadata?.toRoundName as string) || 'next round',
      ctx.metadata?.customMessage as string | undefined,
      ctx.metadata?.accountUrl as string | undefined,
      ctx.metadata?.fullCustomBody as boolean | undefined,
    ),
  REJECTION_NOTIFICATION: (ctx) =>
    getRejectionNotificationTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Your Project',
      (ctx.metadata?.roundName as string) || 'this round',
      ctx.metadata?.customMessage as string | undefined,
      ctx.metadata?.fullCustomBody as boolean | undefined,
    ),

  AWARD_WINNER_NOTIFICATION: (ctx) =>
    getAwardWinnerNotificationTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Your Project',
      (ctx.metadata?.awardName as string) || 'Special Award',
      ctx.metadata?.customMessage as string | undefined,
      ctx.metadata?.accountUrl as string | undefined,
      ctx.metadata?.fullCustomBody as boolean | undefined,
    ),

  AWARD_SELECTION_NOTIFICATION: (ctx) =>
    getAwardSelectionNotificationTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Your Project',
      (ctx.metadata?.awardName as string) || 'Special Award',
      ctx.metadata?.customMessage as string | undefined,
      ctx.metadata?.accountUrl as string | undefined,
    ),

  ACCOUNT_REMINDER: (ctx) =>
    getAccountReminderTemplate(
      ctx.name || '',
      (ctx.metadata?.projectName as string) || 'Your Project',
      (ctx.metadata?.accountUrl as string) || '/accept-invite',
    ),

  // Admin templates
  NEW_APPLICATION: (ctx) =>
    getNewApplicationTemplate(
      (ctx.metadata?.projectName as string) || 'New Project',
      (ctx.metadata?.applicantName as string) || 'Applicant',
      (ctx.metadata?.applicantEmail as string) || '',
      (ctx.metadata?.programName as string) || 'MOPC',
      ctx.linkUrl
    ),

  // Logistics templates (team/attendee-facing)
  FINALIST_REMINDER: (ctx) =>
    getFinalistReminderTemplate(
      ctx.name || '',
      (ctx.metadata?.projectTitle as string) || 'Your project',
      new Date((ctx.metadata?.deadline as string) || Date.now()),
      ctx.linkUrl || '',
    ),
  GRAND_FINAL_DOCS_REMINDER: (ctx) =>
    getGrandFinalDocsReminderTemplate(
      ctx.name || '',
      (ctx.metadata?.projectTitle as string) || 'Your project',
      ctx.metadata?.deadline ? new Date(ctx.metadata.deadline as string) : null,
      ctx.linkUrl || '',
      (ctx.metadata?.missing as string[]) || [],
    ),
  FINALIST_WITHDRAWN: (ctx) =>
    getFinalistWithdrawnTemplate(
      ctx.name || '',
      (ctx.metadata?.projectTitle as string) || 'Your project',
      ctx.metadata?.reason as string | undefined,
    ),
  TRAVEL_CONFIRMED: (ctx) =>
    getTravelConfirmedTemplate(
      ctx.name || '',
      (ctx.metadata?.projectTitle as string) || 'Your project',
      {
        arrivalAt: ctx.metadata?.arrivalAt as string | undefined,
        arrivalFlightNumber: ctx.metadata?.arrivalFlightNumber as string | undefined,
        arrivalAirport: ctx.metadata?.arrivalAirport as string | undefined,
        departureAt: ctx.metadata?.departureAt as string | undefined,
        departureFlightNumber: ctx.metadata?.departureFlightNumber as string | undefined,
        departureAirport: ctx.metadata?.departureAirport as string | undefined,
      },
      ctx.metadata?.hotel as { name: string; address?: string; link?: string } | undefined,
      ctx.metadata?.roomNumber !== undefined || ctx.metadata?.checkInAt !== undefined || ctx.metadata?.checkOutAt !== undefined
        ? {
            roomNumber: ctx.metadata?.roomNumber as string | null | undefined,
            checkInAt: ctx.metadata?.checkInAt as string | null | undefined,
            checkOutAt: ctx.metadata?.checkOutAt as string | null | undefined,
          }
        : undefined,
    ),
  VISA_STATUS_UPDATE: (ctx) =>
    getVisaStatusTemplate(
      ctx.name || '',
      (ctx.metadata?.projectTitle as string) || 'Your project',
      (ctx.metadata?.status as 'INVITATION_SENT' | 'APPOINTMENT_BOOKED' | 'GRANTED' | 'DENIED') || 'INVITATION_SENT',
      ctx.metadata?.note as string | undefined,
    ),
}

/**
 * Resolve the email template for a notification type without sending.
 * Exported for use by preview endpoints.
 */
export function renderNotificationEmail(
  name: string,
  type: string,
  context: NotificationEmailContext,
  subjectOverride?: string,
): EmailTemplate {
  const generator = NOTIFICATION_EMAIL_TEMPLATES[type]
  const template = generator
    ? generator({ ...context, linkUrl: ensureAbsoluteUrl(context.linkUrl), name })
    : getNotificationEmailTemplate(name, subjectOverride || context.title, context.message, ensureAbsoluteUrl(context.linkUrl))
  return subjectOverride ? { ...template, subject: subjectOverride } : template
}

/**
 * Send styled notification email using the appropriate template
 */
export async function sendStyledNotificationEmail(
  email: string,
  name: string,
  type: string,
  context: NotificationEmailContext,
  subjectOverride?: string
): Promise<void> {
  const template = renderNotificationEmail(name, type, context, subjectOverride)
  await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
}

// =============================================================================
// Email Sending Functions
// =============================================================================

/**
 * Send password reset email
 */
export async function sendPasswordResetEmail(
  email: string,
  url: string,
  expiryMinutes: number = 30
): Promise<void> {
  const template = getPasswordResetTemplate(url, expiryMinutes)
  await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
}

/**
 * Send magic link email for authentication
 */
export async function sendMagicLinkEmail(
  email: string,
  url: string
): Promise<void> {
  const expiryMinutes = parseInt(process.env.MAGIC_LINK_EXPIRY || '900') / 60
  const template = getMagicLinkTemplate(url, expiryMinutes)
  await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
}

/**
 * Send generic invitation email (not round-specific)
 */
export async function sendInvitationEmail(
  email: string,
  name: string | null,
  url: string,
  role: string,
  expiryHours?: number
): Promise<void> {
  const template = getGenericInvitationTemplate(name || '', url, role, expiryHours)
  await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
}

/**
 * Send award juror notification — used both for the initial assignment
 * notification and for admin-triggered reminders.
 */
export async function sendAwardJurorNotificationEmail(opts: {
  email: string
  name: string | null
  awardName: string
  url: string
  eligibleCount?: number
  votingEndAt?: Date | null
  customMessage?: string
  isReminder?: boolean
}): Promise<void> {
  const template = getAwardJurorNotificationTemplate(opts.name || '', opts.awardName, opts.url, {
    eligibleCount: opts.eligibleCount,
    votingEndAt: opts.votingEndAt,
    customMessage: opts.customMessage,
    isReminder: opts.isReminder,
  })
  await sendEmail({ to: opts.email, subject: template.subject, text: template.text, html: template.html })
}

/**
 * Send jury invitation email (round-specific)
 */
export async function sendJuryInvitationEmail(
  email: string,
  name: string | null,
  url: string,
  roundName: string
): Promise<void> {
  const template = getJuryInvitationTemplate(name || '', url, roundName)
  await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
}

/**
 * Send evaluation reminder email
 */
export async function sendEvaluationReminderEmail(
  email: string,
  name: string | null,
  pendingCount: number,
  roundName: string,
  deadline: string,
  assignmentsUrl: string
): Promise<void> {
  const template = getEvaluationReminderTemplate(
    name || '',
    pendingCount,
    roundName,
    deadline,
    assignmentsUrl
  )
  await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
}

/**
 * Send announcement email
 */
export async function sendAnnouncementEmail(
  email: string,
  name: string | null,
  title: string,
  message: string,
  ctaText?: string,
  ctaUrl?: string
): Promise<void> {
  const template = getAnnouncementTemplate(
    name || '',
    title,
    message,
    ctaText,
    ctaUrl
  )
  await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
}

/**
 * Send a test email to verify SMTP configuration
 */
export async function sendTestEmail(toEmail: string): Promise<boolean> {
  try {
    const content = `
      ${sectionTitle('Test Email')}
      ${paragraph('This is a test email from the MOPC Portal.')}
      ${infoBox('If you received this, your email configuration is working correctly!', 'success')}
      <p style="color: ${BRAND.textMuted}; margin: 20px 0 0 0; font-size: 13px; text-align: center;">
        Sent at ${new Date().toISOString()}
      </p>
    `
    await sendEmail({
      to: toEmail,
      subject: 'MOPC Portal - Test Email',
      text: 'This is a test email from the MOPC Portal. If you received this, your email configuration is working correctly.',
      html: getEmailWrapper(content),
    })
    return true
  } catch {
    return false
  }
}

/**
 * Verify SMTP connection
 */
export async function verifyEmailConnection(): Promise<boolean> {
  try {
    const { transporter } = await getTransporter()
    await transporter.verify()
    return true
  } catch {
    return false
  }
}

/**
 * Send application confirmation email to applicant
 */
export async function sendApplicationConfirmationEmail(
  email: string,
  applicantName: string,
  projectName: string,
  programName: string,
  customMessage?: string
): Promise<void> {
  const template = getApplicationConfirmationTemplate(
    applicantName,
    projectName,
    programName,
    customMessage
  )
  await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
}

/**
 * Send team member invite email
 */
export async function sendTeamMemberInviteEmail(
  email: string,
  memberName: string,
  projectName: string,
  teamLeadName: string,
  inviteUrl: string
): Promise<void> {
  const template = getTeamMemberInviteTemplate(
    memberName,
    projectName,
    teamLeadName,
    inviteUrl
  )
  await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
}

/**
 * Generate notification email template
 */
function getNotificationEmailTemplate(
  name: string,
  subject: string,
  body: string,
  linkUrl?: string
): EmailTemplate {
  const greeting = name ? `Hello ${name},` : 'Hello,'

  // Format body text preserving line breaks
  const formattedBody = escapeHtml(body).replace(/\n/g, '<br>')

  const content = `
    ${sectionTitle(greeting)}
    <div style="color: ${BRAND.textDark}; font-size: 15px; line-height: 1.7; margin: 20px 0;">
      ${formattedBody}
    </div>
    ${linkUrl ? ctaButton(linkUrl, 'View Details') : ''}
    <p style="color: ${BRAND.textMuted}; margin: 24px 0 0 0; font-size: 13px; text-align: center;">
      You received this email because of your notification preferences on the MOPC Portal.
    </p>
  `

  return {
    subject,
    html: getEmailWrapper(content),
    text: `
${greeting}

${body}

${linkUrl ? `View details: ${linkUrl}` : ''}

---
Monaco Ocean Protection Challenge
Together for a healthier ocean.
    `,
  }
}

/**
 * Send notification email (triggered by in-app notification system)
 */
export async function sendNotificationEmail(
  email: string,
  name: string,
  subject: string,
  body: string,
  linkUrl?: string
): Promise<void> {
  const template = getNotificationEmailTemplate(name, subject, body, ensureAbsoluteUrl(linkUrl))
  await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
}

// =============================================================================
// Mentor onboarding (one-shot, on first MENTOR role grant)
// =============================================================================

function getMentorOnboardingTemplate(name: string, baseUrl: string): EmailTemplate {
  const mentorUrl = `${baseUrl.replace(/\/$/, '')}/mentor`
  const subject = 'Welcome to MOPC mentoring'
  const text = [
    `Hi ${name || 'there'},`,
    '',
    'You have been added as a mentor for the Monaco Ocean Protection Challenge.',
    '',
    'As a mentor, you will:',
    '  • Be matched with one or more shortlisted projects',
    '  • Communicate with project teams in a private workspace',
    '  • Share files, comments, and milestone feedback',
    '  • Help projects sharpen their submissions before the live final',
    '',
    `Your mentor dashboard: ${mentorUrl}`,
    '',
    'If you also have other roles on the platform (e.g. juror), look for the',
    '"Switch View" pill in the top-right of any page to move between dashboards.',
    '',
    'The MOPC team',
  ].join('\n')

  const html = `
<!DOCTYPE html>
<html>
<body style="margin:0;padding:0;background:#f6f8fa;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;color:#0f172a;">
  <div style="max-width:560px;margin:32px auto;background:#fff;border-radius:8px;overflow:hidden;box-shadow:0 1px 3px rgba(0,0,0,0.06);">
    <div style="background:#053d57;padding:24px 28px;color:#fefefe;">
      <h1 style="margin:0;font-size:20px;font-weight:600;">Welcome to MOPC mentoring</h1>
    </div>
    <div style="padding:24px 28px;line-height:1.5;font-size:14px;">
      <p style="margin-top:0;">Hi ${name || 'there'},</p>
      <p>You have been added as a mentor for the Monaco Ocean Protection Challenge.</p>
      <p>As a mentor, you will:</p>
      <ul style="padding-left:20px;">
        <li>Be matched with one or more shortlisted projects</li>
        <li>Communicate with project teams in a private workspace</li>
        <li>Share files, comments, and milestone feedback</li>
        <li>Help projects sharpen their submissions before the live final</li>
      </ul>
      <p style="margin-top:24px;">
        <a href="${mentorUrl}" style="display:inline-block;padding:10px 20px;background:#de0f1e;color:#fff;text-decoration:none;border-radius:6px;font-weight:600;">Open Mentor Dashboard</a>
      </p>
      <p style="margin-top:24px;color:#64748b;font-size:12px;">
        If you also have other roles on the platform, use the "Switch View" pill in the top-right of any page to move between dashboards.
      </p>
    </div>
    <div style="padding:16px 28px;background:#f1f5f9;color:#64748b;font-size:12px;text-align:center;">
      Monaco Ocean Protection Challenge
    </div>
  </div>
</body>
</html>
  `.trim()

  return { subject, text, html }
}

/**
 * Send mentor onboarding email. Idempotency is enforced at the call site
 * (see user.bulkUpdateRoles / user.updateRoles) by checking
 * User.mentorOnboardingSentAt.
 */
export async function sendMentorOnboardingEmail(email: string, name: string | null): Promise<void> {
  const baseUrl = process.env.NEXTAUTH_URL || 'https://monaco-opc.com'
  const template = getMentorOnboardingTemplate(name || '', baseUrl)
  await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
}

// =============================================================================
// Per-team mentor assignment (fires every time a mentor is added to a project)
// =============================================================================

function getMentorTeamAssignmentTemplate(
  name: string,
  projectTitle: string,
  workspaceUrl: string,
): EmailTemplate {
  const subject = `You've been assigned to a new MOPC project: "${projectTitle}"`
  const greeting = name ? `Hi ${name},` : 'Hi there,'
  const text = [
    greeting,
    '',
    `You have been assigned as a mentor to the project "${projectTitle}".`,
    '',
    'You may have co-mentors on this team — you can collaborate together in the project workspace.',
    '',
    `Open the workspace: ${workspaceUrl}`,
    '',
    'The MOPC team',
  ].join('\n')

  const html = `
<!DOCTYPE html>
<html>
<body style="margin:0;padding:0;background:#f6f8fa;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;color:#0f172a;">
  <div style="max-width:560px;margin:32px auto;background:#fff;border-radius:8px;overflow:hidden;box-shadow:0 1px 3px rgba(0,0,0,0.06);">
    <div style="background:#053d57;padding:24px 28px;color:#fefefe;">
      <h1 style="margin:0;font-size:20px;font-weight:600;">New mentor assignment</h1>
    </div>
    <div style="padding:24px 28px;line-height:1.5;font-size:14px;">
      <p style="margin-top:0;">${name ? `Hi ${escapeHtml(name)},` : 'Hi there,'}</p>
      <p>You have been assigned as a mentor to the project <strong>${escapeHtml(projectTitle)}</strong>.</p>
      <p style="margin-top:24px;">
        <a href="${workspaceUrl}" style="display:inline-block;padding:10px 20px;background:#de0f1e;color:#fff;text-decoration:none;border-radius:6px;font-weight:600;">Open Project Workspace</a>
      </p>
      <p style="margin-top:24px;color:#64748b;font-size:12px;">
        You may have co-mentors on this team — you can collaborate together in the project workspace.
      </p>
    </div>
    <div style="padding:16px 28px;background:#f1f5f9;color:#64748b;font-size:12px;text-align:center;">
      Monaco Ocean Protection Challenge
    </div>
  </div>
</body>
</html>
  `.trim()

  return { subject, text, html }
}

/**
 * Send a per-team mentor assignment email. Fires every time a mentor is added
 * to a specific project (distinct from the one-time onboarding email).
 * Idempotency is enforced at the call site via MentorAssignment.notificationSentAt.
 * Never throws — failures are caught and logged.
 */
export async function sendMentorTeamAssignmentEmail(
  email: string,
  name: string | null,
  projectTitle: string,
  projectId: string,
): Promise<void> {
  try {
    const baseUrl = process.env.NEXTAUTH_URL || 'https://monaco-opc.com'
    const workspaceUrl = `${baseUrl.replace(/\/$/, '')}/mentor/workspace/${projectId}`
    const template = getMentorTeamAssignmentTemplate(name || '', projectTitle, workspaceUrl)
    await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
  } catch (error) {
    console.error('[sendMentorTeamAssignmentEmail] failed', { email, projectId, error })
  }
}

export function getTeamMentorIntroductionTemplate(
  recipientName: string | null,
  projectTitle: string,
  mentors: { name: string | null; email: string }[],
  workspaceUrl: string,
  teammates?: { name: string | null; email: string }[],
  customNote?: string,
): EmailTemplate {
  const count = mentors.length
  const subject =
    count === 1
      ? `Your mentor for "${projectTitle}" on MOPC`
      : `Your ${count} mentors for "${projectTitle}" on MOPC`
  const greeting = recipientName ? `Hi ${recipientName},` : 'Hi there,'

  const mentorTextLines = mentors
    .map((m) => `  • ${m.name ?? 'Mentor'} — ${m.email}`)
    .join('\n')
  const teammateTextLines =
    teammates && teammates.length > 0
      ? ['', 'Your team:', ...teammates.map((t) => `  • ${t.name ?? 'Team member'} — ${t.email}`)]
      : []

  const text = [
    greeting,
    '',
    ...(customNote ? [customNote, ''] : []),
    count === 1
      ? `The mentoring round is now open, and your project "${projectTitle}" has a mentor:`
      : `The mentoring round is now open, and your project "${projectTitle}" has ${count} mentors:`,
    '',
    mentorTextLines,
    ...teammateTextLines,
    '',
    'Working with your mentor:',
    '  - Go to the Mentoring section of your applicant portal to message your mentor directly — they are notified by email when you write.',
    '  - Share documents and questions early; your mentor is here to help you sharpen your project before the finals.',
    '  - You can also email your mentor directly using the address above.',
    '',
    `Open your mentoring page: ${workspaceUrl}`,
    '',
    'The MOPC team',
  ].join('\n')

  const noteHtml = customNote ? infoBox(escapeHtml(customNote), 'warning') : ''

  const mentorHtmlList = mentors
    .map(
      (m) => `
        <tr>
          <td style="padding:6px 16px 6px 0;font-weight:600;color:#0f172a;vertical-align:top;">${escapeHtml(m.name ?? 'Mentor')}</td>
          <td style="padding:6px 0;vertical-align:top;"><a href="mailto:${escapeHtml(m.email)}" style="color:#053d57;text-decoration:none;">${escapeHtml(m.email)}</a></td>
        </tr>`,
    )
    .join('')

  const teammatesHtml =
    teammates && teammates.length > 0
      ? `
      <h2 style="margin:24px 0 8px;color:#0f172a;font-size:15px;font-weight:600;">Your team</h2>
      <table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-collapse:collapse;margin:0 0 8px;font-size:14px;">${teammates
        .map(
          (t) => `
        <tr>
          <td style="padding:6px 16px 6px 0;color:#0f172a;vertical-align:top;">${escapeHtml(t.name ?? 'Team member')}</td>
          <td style="padding:6px 0;vertical-align:top;"><a href="mailto:${escapeHtml(t.email)}" style="color:#053d57;text-decoration:none;">${escapeHtml(t.email)}</a></td>
        </tr>`,
        )
        .join('')}</table>`
      : ''

  const instructionsHtml = infoBox(
    `<strong>Working with your mentor</strong><br>` +
      `&bull; Go to the Mentoring section of your applicant portal to message your mentor directly — they are notified by email when you write.<br>` +
      `&bull; Share documents and questions early; your mentor is here to help you sharpen your project before the finals.<br>` +
      `&bull; You can also email your mentor directly using the address above.`,
    'info',
  )

  const content = `
    ${sectionTitle(count === 1 ? 'Meet your mentor' : `Meet your ${count} mentors`)}
    ${paragraph(recipientName ? `Hi ${escapeHtml(recipientName)},` : 'Hi there,')}
    ${noteHtml}
    ${paragraph(
      count === 1
        ? `The mentoring round is now open and a mentor has been assigned to your project <strong>${escapeHtml(projectTitle)}</strong>:`
        : `The mentoring round is now open and <strong>${count}</strong> mentors have been assigned to your project <strong>${escapeHtml(projectTitle)}</strong>:`,
    )}
    <table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-collapse:collapse;margin:8px 0;font-size:14px;">${mentorHtmlList}</table>
    ${teammatesHtml}
    ${instructionsHtml}
    ${ctaButton(workspaceUrl, 'Open Mentor Workspace')}
  `

  const html = getEmailWrapper(content)

  return { subject, text, html }
}

/**
 * Introduce a project team to their assigned mentor(s), with each mentor's
 * name + email so the team can reach out directly. Sent when the MENTORING
 * round opens AND any time a mentor is added to a project whose mentoring
 * round is already open. Never throws.
 */
export async function sendTeamMentorIntroductionEmail(
  recipientEmail: string,
  recipientName: string | null,
  projectTitle: string,
  projectId: string,
  mentors: { name: string | null; email: string }[],
  teammates?: { name: string | null; email: string }[],
  customNote?: string,
): Promise<boolean> {
  try {
    if (mentors.length === 0) return false
    const baseUrl = getBaseUrl()
    const workspaceUrl = `${baseUrl}/applicant/mentor`
    const template = getTeamMentorIntroductionTemplate(
      recipientName,
      projectTitle,
      mentors,
      workspaceUrl,
      teammates,
      customNote,
    )
    await sendEmail({
      to: recipientEmail,
      subject: template.subject,
      text: template.text,
      html: template.html,
    })
    return true
  } catch (error) {
    console.error('[sendTeamMentorIntroductionEmail] failed', { recipientEmail, projectId, error })
    return false
  }
}

export function getMentorBulkAssignmentTemplate(
  name: string,
  projects: {
    title: string
    url: string
    teamMembers?: { name: string | null; email: string }[]
  }[],
  mentorDashboardUrl: string,
  customNote?: string,
): EmailTemplate {
  const count = projects.length
  const subject =
    count === 1
      ? `You've been assigned to a new MOPC project: "${projects[0].title}"`
      : `You've been assigned to ${count} new MOPC projects`
  const greeting = name ? `Hi ${name},` : 'Hi there,'

  const textBlocks = projects.map((p) => {
    const members =
      p.teamMembers && p.teamMembers.length > 0
        ? '\n' +
          p.teamMembers
            .map((m) => `      - ${m.name ?? 'Team member'}: ${m.email}`)
            .join('\n')
        : ''
    return `  • ${p.title} — ${p.url}${members}`
  })
  const text = [
    greeting,
    '',
    ...(customNote ? [customNote, ''] : []),
    count === 1
      ? `You have been assigned as a mentor to a new project:`
      : `You have been assigned as a mentor to ${count} new projects:`,
    '',
    ...textBlocks,
    '',
    'How to mentor on MOPC:',
    '  - Open each project workspace from your Mentor Dashboard to chat with the team, share files, and track milestones.',
    '  - Messages you send in the workspace notify the team by email automatically.',
    '  - You can also email team members directly using the addresses listed above.',
    '',
    `Open your mentor dashboard: ${mentorDashboardUrl}`,
    '',
    'The MOPC team',
  ].join('\n')

  const noteHtml = customNote ? infoBox(escapeHtml(customNote), 'warning') : ''

  const htmlList = projects
    .map((p) => {
      const members =
        p.teamMembers && p.teamMembers.length > 0
          ? `<table role="presentation" cellspacing="0" cellpadding="0" border="0" style="border-collapse:collapse;margin:6px 0 0;font-size:13px;">${p.teamMembers
              .map(
                (m) =>
                  `<tr><td style="padding:3px 16px 3px 0;color:#0f172a;vertical-align:top;">${escapeHtml(m.name ?? 'Team member')}</td><td style="padding:3px 0;vertical-align:top;"><a href="mailto:${escapeHtml(m.email)}" style="color:#053d57;text-decoration:none;">${escapeHtml(m.email)}</a></td></tr>`,
              )
              .join('')}</table>`
          : ''
      return `<li style="margin:10px 0;"><a href="${p.url}" style="color:#053d57;text-decoration:none;font-weight:600;">${escapeHtml(p.title)}</a>${members}</li>`
    })
    .join('')

  const instructionsHtml = infoBox(
    `<strong>How to mentor on MOPC</strong><br>` +
      `&bull; Open each project workspace from your Mentor Dashboard to chat with the team, share files, and track milestones.<br>` +
      `&bull; Messages you send in the workspace notify the team by email automatically.<br>` +
      `&bull; You can also email team members directly using the addresses listed above.`,
    'info',
  )

  const content = `
    ${sectionTitle(count === 1 ? 'New mentor assignment' : `${count} new mentor assignments`)}
    ${paragraph(name ? `Hi ${escapeHtml(name)},` : 'Hi there,')}
    ${noteHtml}
    ${paragraph(count === 1 ? 'You have been assigned as a mentor to a new project:' : `You have been assigned as a mentor to <strong>${count}</strong> new projects:`)}
    <ul style="padding-left:20px;margin:12px 0 20px;color:${BRAND.textDark};font-size:15px;">${htmlList}</ul>
    ${instructionsHtml}
    ${ctaButton(mentorDashboardUrl, 'Open Mentor Dashboard')}
  `

  const html = getEmailWrapper(content)

  return { subject, text, html }
}

/**
 * Send a coalesced mentor-assignment email when one mentor receives multiple
 * project assignments in a single bulk operation. Caller passes the list of
 * NEW assignments (already filtered to exclude any whose notificationSentAt
 * was previously set). Never throws.
 */
export async function sendMentorBulkAssignmentEmail(
  email: string,
  name: string | null,
  projects: { id: string; title: string; teamMembers?: { name: string | null; email: string }[] }[],
  customNote?: string,
): Promise<boolean> {
  try {
    if (projects.length === 0) return false
    const baseUrl = getBaseUrl()
    const enriched = projects.map((p) => ({
      title: p.title,
      url: `${baseUrl}/mentor/workspace/${p.id}`,
      teamMembers: p.teamMembers,
    }))
    const template = getMentorBulkAssignmentTemplate(name || '', enriched, `${baseUrl}/mentor`, customNote)
    await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
    return true
  } catch (error) {
    console.error('[sendMentorBulkAssignmentEmail] failed', { email, error })
    return false
  }
}

// =============================================================================
// Mentor change requests (PR 8) — admin notification when an applicant or admin
// opens a MentorChangeRequest. Mentors are NOT notified (per design decision).
// =============================================================================

function getMentorChangeRequestTemplate(
  projectTitle: string,
  requesterName: string | null,
  reason: string,
  adminDashboardUrl: string,
): EmailTemplate {
  const subject = `Mentor change request for "${projectTitle}"`
  const requesterLabel = requesterName || 'a team member'
  const text = [
    'Hi MOPC admins,',
    '',
    `A mentor change request has been opened by ${requesterLabel} for the project "${projectTitle}".`,
    '',
    'Reason:',
    `"${reason}"`,
    '',
    `Review the request: ${adminDashboardUrl}`,
    '',
    'The MOPC team',
  ].join('\n')

  const html = `
<!DOCTYPE html>
<html>
<body style="margin:0;padding:0;background:#f6f8fa;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;color:#0f172a;">
  <div style="max-width:560px;margin:32px auto;background:#fff;border-radius:8px;overflow:hidden;box-shadow:0 1px 3px rgba(0,0,0,0.06);">
    <div style="background:#053d57;padding:24px 28px;color:#fefefe;">
      <h1 style="margin:0;font-size:20px;font-weight:600;">Mentor change request</h1>
    </div>
    <div style="padding:24px 28px;line-height:1.5;font-size:14px;">
      <p style="margin-top:0;">Hi MOPC admins,</p>
      <p>A mentor change request has been opened by <strong>${escapeHtml(requesterLabel)}</strong> for the project <strong>${escapeHtml(projectTitle)}</strong>.</p>
      <blockquote style="margin:16px 0;padding:12px 16px;background:#f1f5f9;border-left:3px solid #557f8c;border-radius:4px;color:#0f172a;font-style:italic;white-space:pre-wrap;">${escapeHtml(reason)}</blockquote>
      <p style="margin-top:24px;">
        <a href="${adminDashboardUrl}" style="display:inline-block;padding:10px 20px;background:#de0f1e;color:#fff;text-decoration:none;border-radius:6px;font-weight:600;">Review Request</a>
      </p>
      <p style="margin-top:24px;color:#64748b;font-size:12px;">
        Mentors are not notified of change requests; only admins see this.
      </p>
    </div>
    <div style="padding:16px 28px;background:#f1f5f9;color:#64748b;font-size:12px;text-align:center;">
      Monaco Ocean Protection Challenge
    </div>
  </div>
</body>
</html>
  `.trim()

  return { subject, text, html }
}

/**
 * Notify all SUPER_ADMIN / PROGRAM_ADMIN users that a mentor change request
 * has been opened for a project. Sends one email per recipient.
 * Never throws — failures are caught and logged so the calling mutation
 * (mentor.requestChange) never fails because of email infrastructure issues.
 */
export async function sendMentorChangeRequestEmail(
  adminEmails: string[],
  projectTitle: string,
  requesterName: string | null,
  reason: string,
  adminDashboardUrl: string,
): Promise<void> {
  try {
    if (adminEmails.length === 0) {
      console.warn('[sendMentorChangeRequestEmail] no admin recipients; skipping')
      return
    }
    const template = getMentorChangeRequestTemplate(
      projectTitle,
      requesterName,
      reason,
      adminDashboardUrl,
    )
    await Promise.all(
      adminEmails.map((email) =>
        sendEmail({
          to: email,
          subject: template.subject,
          text: template.text,
          html: template.html,
        }).catch((err) => {
          console.error('[sendMentorChangeRequestEmail] send failed', { email, err })
        }),
      ),
    )
  } catch (error) {
    console.error('[sendMentorChangeRequestEmail] failed', { error })
  }
}

function getFinalistConfirmationTemplate(
  name: string,
  projectTitle: string,
  deadlineIso: string,
  confirmUrl: string,
): EmailTemplate {
  const subject = `Grand Finale: confirm your attendance for "${projectTitle}"`
  const greeting = name ? `Hi ${name},` : 'Hi,'
  const text = [
    greeting,
    '',
    `Congratulations — your project "${projectTitle}" has been selected as a finalist`,
    'for the Monaco Ocean Protection Challenge grand finale.',
    '',
    `Please confirm your team's attendance by ${deadlineIso}.`,
    'On the confirmation page you will:',
    '  • Choose which team members will attend',
    '  • Indicate who needs visa support',
    '',
    `Confirm here: ${confirmUrl}`,
    '',
    'If your team cannot attend, please use the same link to decline so',
    'we can offer the slot to a waitlisted team in time.',
    '',
    'The MOPC team',
  ].join('\n')

  const html = `
<!DOCTYPE html>
<html>
<body style="margin:0;padding:0;background:#f6f8fa;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;color:#0f172a;">
  <div style="max-width:560px;margin:32px auto;background:#fff;border-radius:8px;overflow:hidden;box-shadow:0 1px 3px rgba(0,0,0,0.06);">
    <div style="background:#053d57;padding:24px 28px;color:#fefefe;">
      <h1 style="margin:0;font-size:20px;font-weight:600;">You're a Grand Finale finalist</h1>
    </div>
    <div style="padding:24px 28px;line-height:1.5;font-size:14px;">
      <p style="margin-top:0;">${greeting}</p>
      <p>Congratulations — your project <strong>${escapeHtml(projectTitle)}</strong> has been selected as a finalist for the Monaco Ocean Protection Challenge grand finale.</p>
      <p style="margin-top:20px;padding:12px 16px;background:#fef3c7;border-left:3px solid #d97706;border-radius:4px;">
        <strong>Confirm by ${escapeHtml(deadlineIso)}.</strong>
      </p>
      <p>On the confirmation page you'll choose which team members will attend and indicate who needs visa support.</p>
      <p style="margin-top:24px;">
        <a href="${confirmUrl}" style="display:inline-block;padding:10px 20px;background:#de0f1e;color:#fff;text-decoration:none;border-radius:6px;font-weight:600;">Confirm Attendance</a>
      </p>
      <p style="margin-top:24px;color:#64748b;font-size:12px;">
        If your team cannot attend, please use the same link to decline so we can offer the slot to a waitlisted team in time.
      </p>
    </div>
    <div style="padding:16px 28px;background:#f1f5f9;color:#64748b;font-size:12px;text-align:center;">
      Monaco Ocean Protection Challenge
    </div>
  </div>
</body>
</html>
  `.trim()

  return { subject, text, html }
}

/**
 * Send a finalist confirmation email. Failures are intentionally not awaited
 * inside any DB transaction — the calling tRPC mutation logs failures but
 * does not roll back the confirmation row creation.
 */
export async function sendFinalistConfirmationEmail(
  email: string,
  name: string | null,
  projectTitle: string,
  deadline: Date,
  confirmUrl: string,
): Promise<void> {
  const template = getFinalistConfirmationTemplate(name || '', projectTitle, deadline.toISOString(), confirmUrl)
  await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
}

// =============================================================================
// LUNCH (PR 6)
// =============================================================================

type LunchRecapPayload = {
  event: { eventAt: Date | null; venue: string | null } | null
  members: Array<{
    name: string
    project: { name: string } | null
    dish: { name: string } | null
    allergens: string[]
    allergenOther: string | null
  }>
  externals: Array<{
    name: string
    project: { name: string } | null
    dish: { name: string } | null
    allergens: string[]
    allergenOther: string | null
    roleNote?: string | null
  }>
  dishCounts: Record<string, number>
  dietaryCounts: Record<string, number>
  allergenCounts: Record<string, number>
  summary: { total: number; picked: number; missing: number }
}

/**
 * Send a lunch reminder to one attendee whose pick is still missing.
 * Failures are caught at the cron layer; this function may throw on
 * individual failures so the caller can decide.
 */
export async function sendLunchReminderEmail(opts: {
  to: string
  memberName: string
  eventAt: Date
  venue: string | null
  changeDeadline: Date
  pickUrl: string
}): Promise<void> {
  const fmt = new Intl.DateTimeFormat('en-GB', {
    timeZone: 'Europe/Monaco', dateStyle: 'long', timeStyle: 'short',
  })
  const subject = `Pick your lunch dish — deadline ${fmt.format(opts.changeDeadline)} (Monaco)`
  const html = `
<!DOCTYPE html>
<html><body style="font-family:system-ui,-apple-system,sans-serif;background:#f8fafc;padding:24px;">
  <div style="max-width:560px;margin:0 auto;background:white;border-radius:12px;padding:32px;">
    <h2 style="margin:0 0 16px;color:#0f172a;">Pick your lunch dish</h2>
    <p>Hi ${escapeHtml(opts.memberName)},</p>
    <p>You haven't picked your lunch dish for the Monaco Ocean Protection Challenge grand finale yet.</p>
    <p>
      <strong>Event:</strong> ${fmt.format(opts.eventAt)} (Europe/Monaco)<br/>
      ${opts.venue ? `<strong>Venue:</strong> ${escapeHtml(opts.venue)}<br/>` : ''}
      <strong>Deadline to pick:</strong> ${fmt.format(opts.changeDeadline)}
    </p>
    <p style="margin-top:24px;">
      <a href="${opts.pickUrl}" style="display:inline-block;background:#053d57;color:white;padding:12px 24px;border-radius:8px;text-decoration:none;font-weight:600;">Open the picker</a>
    </p>
    <p style="margin-top:24px;color:#64748b;font-size:12px;">
      If you have any questions, reply to this email and we'll help.
    </p>
  </div>
</body></html>`.trim()
  const text = `Pick your lunch dish.
Event: ${opts.eventAt.toISOString()}
${opts.venue ? `Venue: ${opts.venue}\n` : ''}Deadline: ${opts.changeDeadline.toISOString()}
${opts.pickUrl}`
  await sendEmail({ to: opts.to, subject, text, html })
}

/**
 * Invite an external lunch attendee to choose their dish via a tokenized,
 * no-login page. Used for the initial invite (auto on add + admin resend) and
 * for reminder sweeps — one template serves both.
 */
export async function sendExternalDishInviteEmail(opts: {
  to: string
  name: string
  eventAt: Date | null
  venue: string | null
  notes: string | null
  changeDeadline: Date | null
  pickUrl: string
}): Promise<void> {
  const fmt = new Intl.DateTimeFormat('en-GB', {
    timeZone: 'Europe/Monaco', dateStyle: 'long', timeStyle: 'short',
  })
  const subject = 'Choose your lunch dish — Monaco Ocean Protection Challenge'
  const venuePhrase = opts.venue
    ? `lunch at ${escapeHtml(opts.venue)}`
    : 'the Monaco Ocean Protection Challenge lunch'
  const eventLine = opts.eventAt
    ? `<strong>When:</strong> ${escapeHtml(fmt.format(opts.eventAt))} (Europe/Monaco)`
    : ''
  const notesLine = opts.notes ? escapeHtml(opts.notes) : ''
  const content = `
    ${sectionTitle('Choose your lunch dish')}
    ${paragraph(`Hi ${escapeHtml(opts.name)},`)}
    ${paragraph(
      `You are joining us for ${venuePhrase}. Please pick your dish and let us know ` +
        'about any allergies so the kitchen can cater for you.',
    )}
    ${eventLine ? paragraph(eventLine) : ''}
    ${notesLine ? paragraph(notesLine) : ''}
    ${
      opts.changeDeadline
        ? infoBox(
            `<strong>Please choose by ${escapeHtml(fmt.format(opts.changeDeadline))}.</strong>`,
            'warning',
          )
        : ''
    }
    ${ctaButton(opts.pickUrl, 'Choose my dish')}
    ${paragraph(
      `<span style="color:#64748b;font-size:13px;">If you have any questions, reply to this email and we'll help.</span>`,
    )}
  `
  const html = getEmailWrapper(content)
  const text = [
    `Choose your lunch dish — Monaco Ocean Protection Challenge`,
    ``,
    `Hi ${opts.name},`,
    ``,
    `Please pick your dish for ${
      opts.venue ? `lunch at ${opts.venue}` : 'the Monaco Ocean Protection Challenge lunch'
    }.`,
    opts.eventAt ? `When: ${fmt.format(opts.eventAt)} (Europe/Monaco)` : '',
    opts.notes ? opts.notes : '',
    opts.changeDeadline ? `Please choose by: ${fmt.format(opts.changeDeadline)}` : '',
    ``,
    `Choose your dish: ${opts.pickUrl}`,
  ]
    .filter((l) => l !== '')
    .join('\n')
  await sendEmail({ to: opts.to, subject, text, html })
}

/**
 * Send the lunch recap manifest to admins + extra recipients.
 * Caller passes the assembled recap payload from `buildRecapPayload`.
 */
export async function sendLunchRecapEmail(
  recipients: string[],
  payload: LunchRecapPayload,
): Promise<void> {
  if (recipients.length === 0) return
  const fmt = new Intl.DateTimeFormat('en-GB', {
    timeZone: 'Europe/Monaco', dateStyle: 'long', timeStyle: 'short',
  })
  const subject = `Lunch manifest — ${payload.event?.eventAt ? fmt.format(payload.event.eventAt) : 'TBD'}`
  const dishLines = Object.entries(payload.dishCounts)
    .sort(([, a], [, b]) => b - a)
    .map(([name, n]) => `<li>${n}× ${escapeHtml(name)}</li>`).join('')
  const dietaryLines = Object.entries(payload.dietaryCounts)
    .map(([name, n]) => `<li>${n}× ${name.replace('_', ' ').toLowerCase()}</li>`).join('')
  const allergenLines = Object.entries(payload.allergenCounts)
    .sort(([, a], [, b]) => b - a)
    .map(([name, n]) => `<li>${n}× ${name.replace('_', ' ').toLowerCase()}</li>`).join('')
  const formatAllergens = (allergens: string[], other: string | null) =>
    [...allergens.map(a => a.replace('_', ' ').toLowerCase()), other].filter(Boolean).join(', ')
  const memberRows = payload.members.map((r) => `
    <tr>
      <td style="padding:6px 10px;border:1px solid #e2e8f0;">${escapeHtml(r.project?.name ?? '')}</td>
      <td style="padding:6px 10px;border:1px solid #e2e8f0;">${escapeHtml(r.name)}</td>
      <td style="padding:6px 10px;border:1px solid #e2e8f0;">${r.dish ? escapeHtml(r.dish.name) : '<em style="color:#94a3b8;">not picked</em>'}</td>
      <td style="padding:6px 10px;border:1px solid #e2e8f0;">${escapeHtml(formatAllergens(r.allergens, r.allergenOther))}</td>
    </tr>`).join('')
  const externalRows = payload.externals.map((r) => `
    <tr>
      <td style="padding:6px 10px;border:1px solid #e2e8f0;">External${r.project?.name ? ` (with ${escapeHtml(r.project.name)})` : ''}</td>
      <td style="padding:6px 10px;border:1px solid #e2e8f0;">${escapeHtml(r.name)}${r.roleNote ? ` — <em>${escapeHtml(r.roleNote)}</em>` : ''}</td>
      <td style="padding:6px 10px;border:1px solid #e2e8f0;">${r.dish ? escapeHtml(r.dish.name) : '<em style="color:#94a3b8;">not picked</em>'}</td>
      <td style="padding:6px 10px;border:1px solid #e2e8f0;">${escapeHtml(formatAllergens(r.allergens, r.allergenOther))}</td>
    </tr>`).join('')
  const html = `
<!DOCTYPE html>
<html><body style="font-family:system-ui,-apple-system,sans-serif;background:#f8fafc;padding:24px;">
  <div style="max-width:760px;margin:0 auto;background:white;border-radius:12px;padding:32px;">
    <h2 style="margin:0 0 8px;color:#0f172a;">Lunch manifest</h2>
    ${payload.event?.eventAt ? `<p style="color:#475569;">${fmt.format(payload.event.eventAt)}${payload.event.venue ? ` · ${escapeHtml(payload.event.venue)}` : ''}</p>` : ''}
    <p><strong>${payload.summary.picked}/${payload.summary.total} picked</strong>${payload.summary.missing ? ` (${payload.summary.missing} missing)` : ''}.</p>
    <h3 style="margin-top:24px;">Dishes</h3>
    <ul>${dishLines || '<li>None picked yet</li>'}</ul>
    ${dietaryLines ? `<h3>Dietary needs</h3><ul>${dietaryLines}</ul>` : ''}
    <h3>Allergens</h3>
    <ul>${allergenLines || '<li>None reported</li>'}</ul>
    <h3 style="margin-top:24px;">Per-attendee</h3>
    <table style="border-collapse:collapse;width:100%;font-size:14px;">
      <thead><tr>
        <th style="padding:6px 10px;background:#f1f5f9;border:1px solid #e2e8f0;text-align:left;">Team</th>
        <th style="padding:6px 10px;background:#f1f5f9;border:1px solid #e2e8f0;text-align:left;">Name</th>
        <th style="padding:6px 10px;background:#f1f5f9;border:1px solid #e2e8f0;text-align:left;">Dish</th>
        <th style="padding:6px 10px;background:#f1f5f9;border:1px solid #e2e8f0;text-align:left;">Allergies</th>
      </tr></thead>
      <tbody>${memberRows}${externalRows}</tbody>
    </table>
  </div>
</body></html>`.trim()
  const text = `${payload.summary.picked}/${payload.summary.total} picked. See HTML version for the full manifest.`
  for (const to of recipients) {
    await sendEmail({ to, subject, text, html })
  }
}

