import { randomUUID } from 'node:crypto'
import { Resend } from 'resend'
import { requireAdminAuth } from '../auth.js'
import { state } from '../state.js'
import { queueNewsletterIssuesWrite } from '../data.js'
import { escapeHtml } from '../helpers.js'
const BASE = 'https://versebyversewithnate.us'
const NEW_EPISODE_TOPIC_NAME = 'new episode'
function truncate(str, max) {
const clean = String(str || '').trim()
if (clean.length <= max) return clean
return `${clean.slice(0, max - 1).trimEnd()}…`
}
function stripSubjectPrefix(subject) {
return String(subject || '').replace(/^New Episode:?\s*-?\s*/i, '').trim()
}
function slugify(str) {
return String(str || '')
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
.slice(0, 80)
}
function uniqueSlug(base) {
const root = slugify(base) || 'issue'
let candidate = root
let n = 2
while (state.newsletterIssues.some(i => i.slug === candidate)) {
candidate = `${root}-${n}`
n += 1
}
return candidate
}
function extractDescription(text, previewText) {
if (previewText && previewText.trim()) return truncate(previewText, 200)
const paragraphs = String(text || '')
.split(/\n{2,}/)
.map(p => p.replace(/\s+/g, ' ').trim())
.filter(Boolean)
const candidate = paragraphs.find(p => p.length > 60 && !/^[◆✦✍✎▶]/.test(p) && p !== p.toUpperCase())
return truncate(candidate || paragraphs[paragraphs.length - 1] || '', 200)
}
// Strip the raw {{{RESEND_UNSUBSCRIBE_URL}}} placeholder link — it only resolves inside an actual sent email.
function stripUnsubscribeLink(html) {
return String(html || '').replace(
/
]*>\s*]*href="\{\{\{RESEND_UNSUBSCRIBE_URL\}\}\}"[\s\S]*?<\/a>\s*<\/p>/i,
'',
)
}
function buildIssuePageHtml(issue) {
const canonical = `${BASE}/newsletter/${encodeURIComponent(issue.slug)}`
const ogImage = `${BASE}/images/banner.png`
const title = escapeHtml(issue.title)
const description = escapeHtml(issue.description)
const metaBlock = `
${title} — Verse by Verse with Nate
`
const ctaBlock = `