/**
 * 画布内容与渲染产物都走 HTML 字符串，任何来自用户（设计器属性面板）的文本
 * 都必须先转义再拼进标签，否则在渲染期会变成注入点。
 */
export function escapeHtml(value: unknown): string {
  return String(value ?? '')
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;')
    .replaceAll("'", '&#39;');
}

/**
 * 转义之后再把换行折成 <br>。
 * <p>
 * 页脚落款、多行文本常在一个属性里塞多行（AI 导入会把原件页脚与签署行合并成一段），
 * 只转义的话换行符会被 HTML 的空白折叠吃掉，几行内容连成一整片。
 */
export function escapeHtmlMultiline(value: unknown): string {
  return escapeHtml(value).replace(/\r\n?|\n/g, '<br>');
}

/** 拼一段内联样式，过滤掉空值 */
export function cssStyle(style: Record<string, number | string | undefined>): string {
  return Object.entries(style)
    .filter(([, value]) => value !== undefined && value !== '')
    .map(([key, value]) => `${key}:${value}`)
    .join(';');
}