const sanitizeHtml = require('sanitize-html')

// Allowlist for wiki/post body HTML. Anything not listed is stripped. This runs
// on every save so the stored value is already safe; the client re-sanitizes on
// render as defense in depth. Tuned for rich-text content from the admin editor.
const OPTIONS = {
  allowedTags: [
    'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
    'p', 'br', 'hr', 'blockquote', 'pre', 'code',
    'ul', 'ol', 'li',
    'strong', 'b', 'em', 'i', 'u', 's', 'sup', 'sub', 'mark', 'span',
    'a', 'img', 'figure', 'figcaption',
    'table', 'thead', 'tbody', 'tr', 'th', 'td',
  ],
  allowedAttributes: {
    a: ['href', 'name', 'target', 'rel', 'title'],
    img: ['src', 'alt', 'title', 'width', 'height'],
    span: ['data-wiki-slug'], // marks internal wiki links (used from Phase 3)
    th: ['colspan', 'rowspan'],
    td: ['colspan', 'rowspan'],
    // Block alignment from the rich-text editor. `style` is only honored for the
    // properties/values whitelisted in allowedStyles below — everything else in
    // the style attribute is stripped.
    p: ['style'],
    h1: ['style'], h2: ['style'], h3: ['style'],
    h4: ['style'], h5: ['style'], h6: ['style'],
  },
  // Restrict inline styles to text-align (left/right/center/justify) only. Any
  // other CSS property, or an unlisted value, is discarded.
  allowedStyles: {
    '*': {
      'text-align': [/^(left|right|center|justify)$/],
    },
  },
  // http/https for links and images, mailto for links, plus relative URLs so
  // uploaded images (/uploads/...) and internal links (/wiki/...) pass through.
  allowedSchemes: ['http', 'https', 'mailto'],
  allowedSchemesByTag: { img: ['http', 'https'] },
  allowProtocolRelative: false,
  // Force safe rel on links that open a new tab; drop empty/odd attributes.
  transformTags: {
    a: sanitizeHtml.simpleTransform('a', { rel: 'noopener noreferrer nofollow' }, true),
  },
  disallowedTagsMode: 'discard',
}

/**
 * Sanitize a block of body HTML against the allowlist above.
 * Null/empty input is returned unchanged.
 * @param {string|null|undefined} html
 * @returns {string|null|undefined}
 */
function cleanBody(html) {
  if (html == null || html === '') return html
  return sanitizeHtml(String(html), OPTIONS)
}

/**
 * Derive a plain-text excerpt from body HTML. Strips tags, collapses
 * whitespace, and truncates to `max` chars (with an ellipsis). Used as the
 * excerpt fallback when an author leaves the excerpt field blank.
 * @param {string|null|undefined} html
 * @param {number} [max=280]
 * @returns {string|null}
 */
function deriveExcerpt(html, max = 280) {
  if (html == null) return null
  const text = String(html)
    .replace(/<[^>]+>/g, ' ')
    .replace(/\s+/g, ' ')
    .trim()
  if (!text) return null
  return text.length > max ? `${text.slice(0, max - 3)}...` : text
}

module.exports = { cleanBody, deriveExcerpt, OPTIONS }
