import type { DrizzleClient } from '@/server/db/client';
import type { LoadCtx } from '@/server/page-layout/types';
import type { Config } from './config';

const ALLOWED_TAGS = new Set([
  'a',
  'blockquote',
  'br',
  'code',
  'em',
  'h1',
  'h2',
  'h3',
  'h4',
  'h5',
  'h6',
  'hr',
  'li',
  'ol',
  'p',
  'pre',
  'strong',
  'ul',
]);

const DROP_WITH_CONTENT = new Set([
  'embed',
  'iframe',
  'math',
  'noscript',
  'object',
  'script',
  'style',
  'svg',
  'template',
]);

export interface SanitizedRichTextData {
  html: Config['body'];
}

function isSafeHref(href: string): boolean {
  const base = 'https://multi.deal';
  if (!URL.canParse(href, base)) return false;
  const protocol = new URL(href, base).protocol;
  return ['http:', 'https:', 'mailto:', 'tel:'].includes(protocol);
}

async function sanitizeRichText(html: string): Promise<string> {
  const rewriter = new HTMLRewriter().on('*', {
    element(element) {
      const tag = element.tagName.toLowerCase();
      if (DROP_WITH_CONTENT.has(tag)) {
        element.remove();
        return;
      }
      if (!ALLOWED_TAGS.has(tag)) {
        element.removeAndKeepContent();
        return;
      }

      for (const entry of element.attributes) {
        const [name, value] = Array.isArray(entry) ? entry : [entry.name, entry.value];
        const attribute = name.toLowerCase();
        const keepDirection = attribute === 'dir' && ['ltr', 'rtl', 'auto'].includes(value);
        const keepAnchor =
          tag === 'a' && ((attribute === 'href' && isSafeHref(value)) || attribute === 'title');
        const keepListValue =
          ((tag === 'ol' && attribute === 'start') || (tag === 'li' && attribute === 'value')) &&
          /^-?\d+$/.test(value);

        if (!keepDirection && !keepAnchor && !keepListValue) {
          element.removeAttribute(name);
        }
      }
    },
  });

  return rewriter
    .transform(
      new Response(html, {
        headers: { 'content-type': 'text/html; charset=utf-8' },
      }),
    )
    .text();
}

export async function loadData(
  _db: DrizzleClient,
  config: Config,
  _ctx: LoadCtx,
): Promise<SanitizedRichTextData> {
  const [he, en] = await Promise.all([
    sanitizeRichText(config.body.he),
    sanitizeRichText(config.body.en),
  ]);

  return { html: { he, en } };
}
