import { describe, it, expect } from 'vitest';
import { htmlToJsx } from '../html-to-jsx.js';

describe('htmlToJsx — attribute renames', () => {
  it('renames class → className', () => {
    expect(htmlToJsx('<div class="foo">x</div>')).toBe('<div className="foo">x</div>');
  });

  it('renames class inside nested elements', () => {
    const input = '<div class="a"><span class="b">hi</span></div>';
    const expected = '<div className="a"><span className="b">hi</span></div>';
    expect(htmlToJsx(input)).toBe(expected);
  });

  it('renames for → htmlFor on labels', () => {
    expect(htmlToJsx('<label for="id">X</label>')).toBe('<label htmlFor="id">X</label>');
  });

  it('renames tabindex → tabIndex', () => {
    expect(htmlToJsx('<div tabindex="0">x</div>')).toBe('<div tabIndex="0">x</div>');
  });

  it('renames multiple attributes in a single tag', () => {
    const input = '<input class="c" readonly maxlength="10" />';
    const out = htmlToJsx(input);
    expect(out).toContain('className="c"');
    expect(out).toContain('readOnly');
    expect(out).toContain('maxLength="10"');
  });

  it('does not rewrite attribute values that contain "class"', () => {
    // The substring "class" in an attribute value should not be renamed.
    const input = '<div class="has class word" data-x="my class name">y</div>';
    const out = htmlToJsx(input);
    // Expected: only the class ATTRIBUTE is renamed; values unchanged.
    expect(out).toBe('<div className="has class word" data-x="my class name">y</div>');
  });
});

describe('htmlToJsx — void elements', () => {
  it('self-closes img', () => {
    expect(htmlToJsx('<img src="a.png" alt="A">')).toBe('<img src="a.png" alt="A" />');
  });

  it('self-closes br', () => {
    expect(htmlToJsx('line<br>break')).toBe('line<br />break');
  });

  it('self-closes input', () => {
    expect(htmlToJsx('<input type="text" class="f">')).toBe('<input type="text" className="f" />');
  });

  it('self-closes hr', () => {
    expect(htmlToJsx('<hr>')).toBe('<hr />');
  });

  it('leaves already-self-closed void elements alone', () => {
    expect(htmlToJsx('<br />')).toBe('<br />');
    expect(htmlToJsx('<img src="a" />')).toBe('<img src="a" />');
  });

  it('handles void elements in the middle of content', () => {
    const input = '<p>hello<br>world<br>!</p>';
    expect(htmlToJsx(input)).toBe('<p>hello<br />world<br />!</p>');
  });
});

describe('htmlToJsx — inline style conversion', () => {
  it('converts a single-declaration style', () => {
    const input = '<div style="color: red">x</div>';
    const out = htmlToJsx(input);
    expect(out).toBe("<div style={{ color: 'red' }}>x</div>");
  });

  it('converts multiple declarations and camelCases property names', () => {
    const input = '<div style="color: red; font-size: 14px; background-color: blue">x</div>';
    const out = htmlToJsx(input);
    expect(out).toBe("<div style={{ color: 'red', fontSize: '14px', backgroundColor: 'blue' }}>x</div>");
  });

  it('handles empty style', () => {
    expect(htmlToJsx('<div style="">x</div>')).toBe('<div style={{}}>x</div>');
  });

  it('escapes single quotes inside values', () => {
    const input = `<div style="font-family: 'Helvetica Neue'">x</div>`;
    const out = htmlToJsx(input);
    expect(out).toBe("<div style={{ fontFamily: '\\'Helvetica Neue\\'' }}>x</div>");
  });

  it('strips trailing semicolons and extra spacing', () => {
    const input = '<div style="color:red;  font-size: 14px ;">x</div>';
    const out = htmlToJsx(input);
    expect(out).toBe("<div style={{ color: 'red', fontSize: '14px' }}>x</div>");
  });
});

describe('htmlToJsx — idempotence', () => {
  it('is a no-op on already-transformed input', () => {
    const jsxLike = '<div className="a"><input type="text" /><br /></div>';
    expect(htmlToJsx(jsxLike)).toBe(jsxLike);
  });
});

describe('htmlToJsx — empty / degenerate input', () => {
  it('returns empty string for empty input', () => {
    expect(htmlToJsx('')).toBe('');
  });

  it('returns text-only input unchanged', () => {
    expect(htmlToJsx('Loading...')).toBe('Loading...');
  });
});

describe('htmlToJsx — realistic Tailwind-adapter output', () => {
  it('transforms a typical table produced by the adapter', () => {
    const input =
      '<table class="w-full text-left border-collapse">' +
      '<thead><tr><th class="px-4 py-2 font-semibold">Title</th></tr></thead>' +
      '<tbody><tr class="hover:bg-gray-50"><td class="px-4 py-2">Hello</td></tr></tbody>' +
      '</table>';
    const out = htmlToJsx(input);
    expect(out).toContain('className="w-full text-left border-collapse"');
    expect(out).toContain('className="px-4 py-2 font-semibold"');
    expect(out).toContain('className="hover:bg-gray-50"');
    expect(out).not.toContain('class=');
  });

  it('transforms a form-group with inputs', () => {
    const input =
      '<div class="space-y-4">' +
      '<label for="title" class="text-sm">Title</label>' +
      '<input type="text" class="border rounded px-2 py-1">' +
      '</div>';
    const out = htmlToJsx(input);
    expect(out).toContain('htmlFor="title"');
    expect(out).toContain('className="text-sm"');
    expect(out).toContain('<input type="text" className="border rounded px-2 py-1" />');
  });
});
