import { htmlToTextWithLineBreaks } from 'src/utils'

describe('htmlToTextWithLineBreaks', () => {
  test('empty input passes through', () => {
    expect(htmlToTextWithLineBreaks('')).toBe('')
  })

  test('single paragraph', () => {
    expect(htmlToTextWithLineBreaks('<p>Hello world</p>')).toBe('Hello world')
  })

  test('two paragraphs separated by a blank line', () => {
    expect(htmlToTextWithLineBreaks('<p>First</p><p>Second</p>')).toBe('First\n\nSecond')
  })

  test('br becomes newline inside a paragraph', () => {
    expect(htmlToTextWithLineBreaks('<p>Line 1<br>Line 2</p>')).toBe('Line 1\nLine 2')
    expect(htmlToTextWithLineBreaks('<p>Line 1<br/>Line 2</p>')).toBe('Line 1\nLine 2')
    expect(htmlToTextWithLineBreaks('<p>Line 1<br />Line 2</p>')).toBe('Line 1\nLine 2')
  })

  test('blockquote prefixes each line with "> "', () => {
    expect(
      htmlToTextWithLineBreaks('<p>Lead</p><blockquote><p>Quoted line</p></blockquote>')
    ).toBe('Lead\n\n> Quoted line')
  })

  test('multiline blockquote prefixes every inner line', () => {
    expect(
      htmlToTextWithLineBreaks('<blockquote>First<br>Second</blockquote>')
    ).toBe('> First\n> Second')
  })

  test('pre preserves internal whitespace', () => {
    expect(htmlToTextWithLineBreaks('<pre>  indented\n  line</pre>')).toBe(
      'indented\n  line'
    )
  })

  test('pre/code wraps source with paragraph breaks', () => {
    expect(
      htmlToTextWithLineBreaks('<p>Before</p><pre><code>a\nb</code></pre><p>After</p>')
    ).toBe('Before\n\na\nb\n\nAfter')
  })

  test('inline code keeps whitespace and text content', () => {
    expect(htmlToTextWithLineBreaks('<p>run <code>npm install</code> first</p>')).toBe(
      'run npm install first'
    )
  })

  test('list items become bulleted lines', () => {
    expect(htmlToTextWithLineBreaks('<ul><li>Alpha</li><li>Beta</li></ul>')).toBe(
      '• Alpha\n• Beta'
    )
  })

  test('html entities are decoded', () => {
    expect(htmlToTextWithLineBreaks('<p>it&#39;s me &amp; you</p>')).toBe("it's me & you")
    expect(htmlToTextWithLineBreaks('<p>a&nbsp;b</p>')).toBe('a b')
    expect(
      htmlToTextWithLineBreaks('<p>&lt;tag&gt; &quot;quoted&quot;</p>')
    ).toBe('<tag> "quoted"')
  })

  test('stray unknown tags are stripped but inner text kept', () => {
    expect(htmlToTextWithLineBreaks('<span>kept</span>')).toBe('kept')
  })

  test('collapses 3+ consecutive newlines into a paragraph break', () => {
    expect(htmlToTextWithLineBreaks('<p>A</p><p></p><p></p><p>B</p>')).toBe('A\n\nB')
  })

  test('blockquote + paragraph adjacency', () => {
    expect(
      htmlToTextWithLineBreaks('<blockquote><p>q</p></blockquote><p>reply</p>')
    ).toBe('> q\n\nreply')
  })

  test('five paragraphs each separated by a blank line', () => {
    const html = '<p>One</p><p>Two</p><p>Three</p><p>Four</p><p>Five</p>'
    expect(htmlToTextWithLineBreaks(html)).toBe(
      'One\n\nTwo\n\nThree\n\nFour\n\nFive'
    )
  })

  test('pixelfed server-side nl2br output preserves single-line breaks', () => {
    // Pixelfed's StatusTransformer does nl2br(autolink(...)), so stored HTML
    // for a multi-line composer input is one <p> with <br /> separators.
    const html = '<p>Line one<br />Line two<br />Line three</p>'
    expect(htmlToTextWithLineBreaks(html)).toBe('Line one\nLine two\nLine three')
  })

  test('URL anchor substitutes href so scheme survives into the output', () => {
    // Mastodon/Pixelfed anchors drop the scheme from visible text — stripping
    // blindly would leave `example.com/foo`, which AutolinkText's linkRegex
    // won't match. Substituting href keeps the URL tappable.
    expect(
      htmlToTextWithLineBreaks(
        '<p><a href="https://example.com/foo">example.com/foo</a></p>'
      )
    ).toBe('https://example.com/foo')
  })

  test('mention anchor keeps inner text so mention regex still fires', () => {
    expect(
      htmlToTextWithLineBreaks(
        '<p><a href="https://srv/@user" class="u-url mention">@<span>user</span></a></p>'
      )
    ).toBe('@user')
  })

  test('hashtag anchor keeps inner text so hashtag regex still fires', () => {
    expect(
      htmlToTextWithLineBreaks(
        '<p><a href="https://srv/tags/foo" class="mention hashtag" rel="tag">#<span>foo</span></a></p>'
      )
    ).toBe('#foo')
  })

  test('anchor with no href falls back to inner text', () => {
    expect(htmlToTextWithLineBreaks('<p><a>label</a></p>')).toBe('label')
  })

  test('URL anchor with single-quoted href', () => {
    expect(
      htmlToTextWithLineBreaks(
        "<p><a href='https://example.com/foo'>example.com/foo</a></p>"
      )
    ).toBe('https://example.com/foo')
  })

  // Profile-field values (Mastodon `Account.fields[].value`) reuse this same
  // path. These lock the reuse contract ProfileFields depends on: a verified
  // rel="me" link value must collapse to its bare href so AutolinkText can
  // re-shorten it and keep the full href as the tap target.
  test('rel="me" field value with invisible/ellipsis spans yields bare href', () => {
    expect(
      htmlToTextWithLineBreaks(
        '<a href="https://shork.xyz" rel="me"><span class="invisible">https://</span><span>shork.xyz</span><span class="invisible"></span></a>'
      )
    ).toBe('https://shork.xyz')
  })

  test('plain-text field value passes through unchanged', () => {
    expect(htmlToTextWithLineBreaks('they/them')).toBe('they/them')
  })

  test('federated mention-style field value keeps the full @handle@host', () => {
    expect(
      htmlToTextWithLineBreaks(
        '<a href="https://host/@handle" class="u-url mention">@<span>handle@host</span></a>'
      )
    ).toBe('@handle@host')
  })
})
