import { expect } from 'vitest';
import reactRenderer from '@astrojs/react/server.js';
import type { experimental_AstroContainer } from 'astro/container';
import type { AstroComponentFactory } from 'astro/runtime/server/index.js';

export type BodyRenderContainer = experimental_AstroContainer;

let containerPromise: Promise<experimental_AstroContainer> | null = null;

export async function getBodyRenderContainer(): Promise<experimental_AstroContainer> {
  if (!containerPromise) {
    containerPromise = (async () => {
      const { experimental_AstroContainer: AstroContainer } = await import('astro/container');
      const astroContainer = await AstroContainer.create();
      astroContainer.addServerRenderer({ renderer: reactRenderer });
      astroContainer.addClientRenderer({
        name: '@astrojs/react',
        entrypoint: '@astrojs/react/client.js',
      });
      return astroContainer;
    })();
  }
  return containerPromise;
}

export async function renderBodyComponent(
  component: AstroComponentFactory,
  props: Record<string, unknown> = {},
): Promise<string> {
  const container = await getBodyRenderContainer();
  return container.renderToString(component, { props });
}

export const INDEX_SITE_NAME = 'Wave 2 test site';

export const INDEX_MOD_CARDS = [
  { id: 'content', name: 'Content', tagline: 'Posts and pages', layer: 'L2' },
];

export const INDEX_HERO_SAFE = '<p>Hero body copy</p>';
export const INDEX_HERO_XSS = '<p>Hero body copy</p><script>alert("xss")</script>';

export const INDEX_POSTS = [
  { slug: 'alpha-post', title: 'Alpha post', createdAt: '2026-06-18T10:00:00.000Z' },
  { slug: 'beta-post', title: 'Beta post', createdAt: '2026-06-01T08:00:00.000Z' },
];

export const INDEX_POSTS_NO_DATE = [
  { slug: 'no-date-post', title: 'No date post', createdAt: '' },
];

export const SEARCH_HIT = {
  slug: 'search-hit',
  title: 'Search hit title',
  snippetHtml: '<p>Result snippet</p><script>evil()</script>',
};

export function assertNoMainElement(html: string): void {
  expect(html).not.toMatch(/<main\b/);
}

export function assertSiteNameInH1(html: string, siteName: string): void {
  expect(html).toMatch(/<h1\b/);
  expect(html).toContain(siteName);
}

export function assertIndexEmptyState(html: string): void {
  expect(html).toContain('No posts yet.');
}

export function assertHeroSanitized(html: string): void {
  expect(html).toContain('Hero body copy');
  expect(html).not.toMatch(/<script\b/i);
  expect(html).toContain('cms-body');
}

export function assertSearchInputHasNoPlaceholder(html: string): void {
  expect(html).not.toMatch(/placeholder\s*=/i);
}

export function assertNotFoundHomeLink(html: string): void {
  expect(html).toMatch(/<h1\b/);
  expect(html).toMatch(/href="\/"/);
}

export function assertTimeElementRendered(html: string, isoString: string): void {
  const escaped = isoString.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  expect(html).toMatch(new RegExp(`<time\\b[^>]*datetime="${escaped}"`));
}

export function assertNoTimeElement(html: string): void {
  expect(html).not.toMatch(/<time\b/);
}
