import sanitizeHtml from 'sanitize-html';
import { SITE_URL } from '../consts';

/** Sanitize и нормализация HTML тела поста для RSS `<content:encoded>`. */
export function sanitizeForRss(html: string): string {
  const absolutized = html.replace(/(src|href)=["']\/uploads\//g, `$1="${SITE_URL}/uploads/`);
  return sanitizeHtml(absolutized, {
    allowedTags: [
      'p', 'br', 'strong', 'em', 'b', 'i', 'u', 's',
      'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
      'a', 'img',
      'ul', 'ol', 'li',
      'blockquote', 'pre', 'code',
      'table', 'thead', 'tbody', 'tr', 'th', 'td',
      'div', 'span', 'hr',
    ],
    allowedAttributes: {
      a: ['href', 'title', 'rel', 'target'],
      img: ['src', 'alt', 'title', 'width', 'height'],
      div: ['align'],
      span: ['align'],
      p: ['align'],
      td: ['colspan', 'rowspan'],
      th: ['colspan', 'rowspan'],
    },
    transformTags: {
      a: (tagName, attribs) => ({
        tagName,
        attribs: {
          ...attribs,
          target: '_blank',
          rel: 'noopener noreferrer',
        },
      }),
    },
    allowedSchemes: ['http', 'https', 'mailto'],
  });
}

/** Экранировать строку для XML-атрибутов и текстовых нод. */
export function xmlEscape(s: string): string {
  return String(s)
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&apos;');
}

/** Завернуть в CDATA, нейтрализовав `]]>` внутри. */
export function cdata(s: string): string {
  return `<![CDATA[${String(s).replace(/]]>/g, ']]]]><![CDATA[>')}]]>`;
}

/** Текстовое описание из HTML (для `<description>`). */
export function plainTextExcerpt(html: string, max = 500): string {
  const txt = html
    .replace(/<style[\s\S]*?<\/style>/gi, ' ')
    .replace(/<script[\s\S]*?<\/script>/gi, ' ')
    .replace(/<[^>]+>/g, ' ')
    .replace(/&nbsp;/g, ' ')
    .replace(/&amp;/g, '&')
    .replace(/&lt;/g, '<')
    .replace(/&gt;/g, '>')
    .replace(/&quot;/g, '"')
    .replace(/\s+/g, ' ')
    .trim();
  if (txt.length <= max) return txt;
  return txt.slice(0, max).replace(/\s+\S*$/, '') + '…';
}

/** Построить полный RSS 2.0 XML с CDATA-завёрнутым content:encoded. */
export function buildRss(opts: {
  title: string;
  description: string;
  selfUrl: string;
  language: string;
  items: Array<{
    title: string;
    link: string;
    pubDate: Date;
    description: string;
    contentHtml: string;
    author: string;
    categories: string[];
  }>;
}): string {
  const { title, description, selfUrl, language, items } = opts;
  const lastBuild = new Date().toUTCString();
  const itemsXml = items
    .map((it) => `    <item>
      <title>${cdata(it.title)}</title>
      <link>${xmlEscape(it.link)}</link>
      <guid isPermaLink="true">${xmlEscape(it.link)}</guid>
      <pubDate>${it.pubDate.toUTCString()}</pubDate>
      <dc:creator>${cdata(it.author)}</dc:creator>
${it.categories.map((c) => `      <category>${cdata(c)}</category>`).join('\n')}
      <description>${cdata(it.description)}</description>
      <content:encoded>${cdata(it.contentHtml)}</content:encoded>
    </item>`)
    .join('\n');

  return `<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>${cdata(title)}</title>
    <link>${xmlEscape(SITE_URL + '/')}</link>
    <atom:link href="${xmlEscape(selfUrl)}" rel="self" type="application/rss+xml" />
    <description>${cdata(description)}</description>
    <language>${language}</language>
    <lastBuildDate>${lastBuild}</lastBuildDate>
    <ttl>60</ttl>
${itemsXml}
  </channel>
</rss>
`;
}
