import { describe, expect, it } from 'vitest';

import { sanitizeSVGContent } from './sanitize';

describe('sanitizeSVGContent', () => {
  it('should preserve safe SVG elements and attributes', () => {
    const safeSvg = `
      <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
        <circle cx="50" cy="50" r="40" fill="red" stroke="blue" stroke-width="2" />
        <rect x="10" y="10" width="30" height="30" fill="green" />
        <path d="M10,20 L30,40" stroke="black" />
      </svg>
    `;

    const sanitized = sanitizeSVGContent(safeSvg);

    expect(sanitized).toContain('<svg');
    expect(sanitized).toContain('xmlns="http://www.w3.org/2000/svg"');
    expect(sanitized).toContain('<circle');
    expect(sanitized).toContain('fill="red"');
    expect(sanitized).toContain('<rect');
    expect(sanitized).toContain('<path');
  });

  it('should remove dangerous script tags', () => {
    const maliciousSvg = `
      <svg xmlns="http://www.w3.org/2000/svg">
        <script>alert('XSS')</script>
        <circle cx="50" cy="50" r="40" fill="red" />
      </svg>
    `;

    const sanitized = sanitizeSVGContent(maliciousSvg);

    expect(sanitized).not.toContain('<script>');
    expect(sanitized).not.toContain('alert');
    expect(sanitized).toContain('<svg');
  });

  it('should remove dangerous event handler attributes', () => {
    const maliciousSvg = `
      <svg xmlns="http://www.w3.org/2000/svg">
        <circle cx="50" cy="50" r="40" fill="red" onclick="alert('click')" onload="alert('load')" />
        <rect width="10" height="10" onMouseOver='alert("hover")' onfocus=alert(1) />
      </svg>
    `;

    const sanitized = sanitizeSVGContent(maliciousSvg);

    expect(sanitized).not.toContain('onclick');
    expect(sanitized).not.toContain('onload');
    expect(sanitized).not.toContain('onMouseOver');
    expect(sanitized).not.toContain('onfocus');
    expect(sanitized).toContain('<circle');
    expect(sanitized).toContain('fill="red"');
  });

  it('should not leave a recombined event handler after stripping', () => {
    // Removing the inner handler in a single pass would splice ` on` + `click="y"` back into a
    // fresh ` onclick="y"`; the scrub must repeat until no handler remains.
    const malicious = `<svg xmlns="http://www.w3.org/2000/svg"><circle on onclick="x"click="y" /></svg>`;

    const sanitized = sanitizeSVGContent(malicious);

    expect(sanitized).not.toMatch(/\son[a-z]+\s*=/i);
  });

  it('should remove dangerous embed and object tags', () => {
    const maliciousSvg = `
      <svg xmlns="http://www.w3.org/2000/svg">
        <object data="malicious.swf"></object>
        <embed src="malicious.swf"></embed>
        <circle cx="50" cy="50" r="40" fill="red" />
      </svg>
    `;

    const sanitized = sanitizeSVGContent(maliciousSvg);

    // Note: DOMPurify with SVG profile may still allow some elements
    // The key security protection is removing script and event handlers
    expect(sanitized).toContain('<circle');
    expect(sanitized).toContain('fill="red"');
  });

  it('should handle empty or invalid SVG content gracefully', () => {
    expect(sanitizeSVGContent('')).toBe('');
    expect(sanitizeSVGContent('<invalid>content</invalid>')).toBe('');
  });

  it('should preserve complex SVG structures while removing threats', () => {
    const complexSvg = `
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
        <defs>
          <linearGradient id="grad1">
            <stop offset="0%" stop-color="red" />
            <stop offset="100%" stop-color="blue" />
          </linearGradient>
        </defs>
        <g transform="translate(50,50)">
          <script>malicious()</script>
          <circle cx="50" cy="50" r="40" fill="url(#grad1)" onclick="hack()" />
          <text x="50" y="60" text-anchor="middle" onload="evil()">Hello</text>
        </g>
      </svg>
    `;

    const sanitized = sanitizeSVGContent(complexSvg);

    // Should preserve safe structure (assert by property, not exact serialization —
    // whitespace/self-closing handling varies across DOM engines).
    expect(sanitized).toContain('<svg');
    expect(sanitized).toContain('viewBox="0 0 200 200"');
    expect(sanitized).toContain('<linearGradient id="grad1"');
    expect(sanitized).toContain('stop-color="red"');
    expect(sanitized).toContain('transform="translate(50,50)"');

    // Should strip all threats regardless of engine
    expect(sanitized).not.toContain('<script');
    expect(sanitized).not.toContain('malicious');
    expect(sanitized).not.toContain('onclick');
    expect(sanitized).not.toContain('onload');
    expect(sanitized).not.toContain('hack()');
    expect(sanitized).not.toContain('evil()');
  });
});
