import assert from 'node:assert/strict';
import test from 'node:test';
import { pageInternals } from './mindspace-pages.mjs';

test('normalizePageInput trims values and constrains templates', () => {
  const result = pageInternals.normalizePageInput({
    title: '  页面标题  ',
    content: '  页面正文  ',
    templateId: 'unknown-template',
  });

  assert.equal(result.title, '页面标题');
  assert.equal(result.content, '页面正文');
  assert.equal(result.templateId, 'editorial');
  assert.equal(result.contentBytes, Buffer.byteLength('页面正文'));
});

test('normalizePageInput rejects empty and oversized page content', () => {
  assert.throws(
    () => pageInternals.normalizePageInput({ title: '', content: '正文' }),
    { code: 'invalid_page_input' },
  );
  assert.throws(
    () =>
      pageInternals.normalizePageInput({
        title: '页面',
        content: '文'.repeat(400_000),
      }),
    { code: 'page_content_too_large' },
  );
});

test('normalizePageInput maps html content to static-html template', () => {
  const result = pageInternals.normalizePageInput({
    title: '页面',
    content: '<!doctype html><html><body>Hi</body></html>',
    contentFormat: 'html',
  });
  assert.equal(result.contentFormat, 'html');
  assert.equal(result.templateId, 'static-html');
  assert.equal(result.pageType, 'html');
});

test('renderHtmlPreview injects restrictive CSP', () => {
  const html = pageInternals.renderHtmlPreview(
    '<!doctype html><html><head></head><body><h1>Hi</h1></body></html>',
  );
  assert.match(html, /Content-Security-Policy/);
  assert.match(html, /script-src 'none'/);
});

test('renderPublicationHtml serves html pages without escaping markup', () => {
  const html = pageInternals.renderPublicationHtml({
    page_type: 'html',
    title: '麻婆豆腐',
    summary: '川菜',
    template_id: 'static-html',
    version_no: 1,
    content: '<!doctype html><html><head><title>麻婆豆腐</title></head><body><h1>麻婆豆腐</h1></body></html>',
  });
  assert.match(html, /<h1>麻婆豆腐<\/h1>/);
  assert.doesNotMatch(html, /&lt;h1&gt;/);
  assert.doesNotMatch(html, /MINDSPACE/);
});

test('preview rendering escapes active HTML and emits a restrictive CSP', () => {
  const html = pageInternals.renderPreviewHtml({
    title: '<script>alert(1)</script>',
    summary: '<img src=x onerror=alert(1)>',
    content: '# 标题\n\n<script>alert(2)</script>',
    templateId: 'report',
    versionNo: 2,
  });

  assert.match(html, /Content-Security-Policy/);
  assert.match(html, /default-src 'none'/);
  assert.doesNotMatch(html, /<script>alert/);
  assert.match(html, /&lt;script&gt;alert/);
  assert.match(html, /DRAFT · V2/);
});

test('previewContentSecurityPolicy allows external assets for html pages', () => {
  const htmlCsp = pageInternals.previewContentSecurityPolicy('html');
  assert.match(htmlCsp, /style-src 'unsafe-inline' https:/);
  assert.match(htmlCsp, /img-src data: https:/);

  const markdownCsp = pageInternals.previewContentSecurityPolicy('markdown');
  assert.match(markdownCsp, /style-src 'unsafe-inline'/);
  assert.doesNotMatch(markdownCsp, /https:/);
});

test('buildPageDeleteSummary lists cascade delete impact', () => {
  const lines = pageInternals.buildPageDeleteSummary({
    page: { title: '麻婆豆腐', versionCount: 2 },
    onlinePublication: { publicUrl: '/u/john/pages/mapo' },
    offlinePublicationCount: 1,
    linkedAssets: [{ id: 'a1' }, { id: 'a2' }],
    linkedAssetBytes: 2048,
    linkedAgentJobCount: 1,
    preservesSourceAsset: true,
  });
  assert.match(lines[0], /麻婆豆腐/);
  assert.ok(lines.some((line) => line.includes('在线公开链接')));
  assert.ok(lines.some((line) => line.includes('原始上传资料不会被删除')));
});
