import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import { renderRichText, safeHref } from './rich-text';

function show(text: string, names: string[] = []) {
  render(<div data-testid="out">{renderRichText(text, names)}</div>);
  return screen.getByTestId('out');
}

describe('renderRichText', () => {
  it('renders bold, italic and strikethrough', () => {
    const el = show('*bold* _italic_ ~gone~');
    expect(el.querySelector('strong')?.textContent).toBe('bold');
    expect(el.querySelector('em')?.textContent).toBe('italic');
    expect(el.querySelector('del')?.textContent).toBe('gone');
  });

  it('nests styles', () => {
    const el = show('*bold with _italic_ inside*');
    const strong = el.querySelector('strong');
    expect(strong?.textContent).toBe('bold with italic inside');
    expect(strong?.querySelector('em')?.textContent).toBe('italic');
  });

  it('leaves markup inside code completely literal', () => {
    const el = show('use `*not bold*` here');
    expect(el.querySelector('code')?.textContent).toBe('*not bold*');
    expect(el.querySelector('strong')).toBeNull();
  });

  it('renders a fenced code block', () => {
    const el = show('```\nconst a = 1;\n```');
    expect(el.querySelector('pre.miu-code-block')?.textContent).toBe('const a = 1;\n');
    expect(el.querySelector('code')).not.toBeNull();
  });

  it('does not treat arithmetic or a lone marker as formatting', () => {
    const el = show('5 * 3 = 15 and a lone * plus snake_case_name');
    expect(el.querySelector('strong')).toBeNull();
    expect(el.querySelector('em')).toBeNull();
    expect(el.textContent).toBe('5 * 3 = 15 and a lone * plus snake_case_name');
  });

  it('linkifies http(s) and www URLs without swallowing trailing punctuation', () => {
    const el = show('see https://example.com/a?b=1, ok');
    const a = el.querySelector('a');
    expect(a?.getAttribute('href')).toBe('https://example.com/a?b=1');
    expect(a?.textContent).toBe('https://example.com/a?b=1');
    expect(a?.getAttribute('rel')).toContain('noopener');
    expect(el.textContent).toContain(', ok');
  });

  it('never renders a javascript: URL as a link (XSS guard)', () => {
    expect(safeHref('javascript:alert(1)')).toBeNull();
    expect(safeHref('data:text/html,<script>')).toBeNull();
    expect(safeHref('https://ok.example')).toBe('https://ok.example/');
    // and it is not linkified in message text either
    const el = show('javascript:alert(1)');
    expect(el.querySelector('a')).toBeNull();
  });

  it('escapes nothing as HTML — angle brackets stay text', () => {
    const el = show('<img src=x onerror=alert(1)>');
    expect(el.querySelector('img')).toBeNull();
    expect(el.textContent).toBe('<img src=x onerror=alert(1)>');
  });

  it('still highlights @mentions alongside formatting', () => {
    const el = show('*hi* @Sofia Ramirez', ['Sofia Ramirez']);
    expect(el.querySelector('strong')?.textContent).toBe('hi');
    expect(el.querySelector('.miu-mention')?.textContent).toBe('@Sofia Ramirez');
  });

  it('returns plain text unchanged when there is no markup', () => {
    expect(show('just a normal message').textContent).toBe('just a normal message');
  });
});
