"""Unit tests for the Patreon ProseMirror→HTML body converter (#842).

Patreon moved the post body from the flat `content` HTML field (now null) to
`content_json_string` (a ProseMirror doc). PURE module → no DB, fast lane.
"""

from __future__ import annotations

import json

from backend.app.utils.prosemirror import post_body_html, prosemirror_to_html


def _doc(*nodes) -> str:
    return json.dumps({"type": "doc", "content": list(nodes)})


def test_paragraph_text_and_hardbreak():
    doc = _doc({
        "type": "paragraph",
        "content": [
            {"type": "text", "text": "Hi there"},
            {"type": "hardBreak"},
            {"type": "text", "text": "line two"},
        ],
    })
    assert prosemirror_to_html(doc) == "<p>Hi there<br>line two</p>"


def test_marks_bold_italic_link():
    doc = _doc({
        "type": "paragraph",
        "content": [
            {"type": "text", "marks": [{"type": "bold"}], "text": "B"},
            {"type": "text", "marks": [{"type": "italic"}], "text": "I"},
            {
                "type": "text",
                "marks": [{"type": "link", "attrs": {"href": "https://x.test/a"}}],
                "text": "L",
            },
        ],
    })
    assert prosemirror_to_html(doc) == (
        '<p><strong>B</strong><em>I</em><a href="https://x.test/a">L</a></p>'
    )


def test_image_node_emits_img_with_cdn_src():
    doc = _doc({
        "type": "image",
        "attrs": {"src": "https://cdn.test/p/post/1/abc/1.gif?token-hash=z", "alt": None},
    })
    out = prosemirror_to_html(doc)
    assert out == '<img src="https://cdn.test/p/post/1/abc/1.gif?token-hash=z" alt="">'


def test_lists_and_heading():
    doc = _doc(
        {"type": "heading", "attrs": {"level": 2},
         "content": [{"type": "text", "text": "Status"}]},
        {"type": "bulletList", "content": [
            {"type": "listItem", "content": [
                {"type": "paragraph", "content": [{"type": "text", "text": "one"}]}]},
        ]},
    )
    assert prosemirror_to_html(doc) == (
        "<h2>Status</h2><ul><li><p>one</p></li></ul>"
    )


def test_text_is_html_escaped():
    doc = _doc({"type": "paragraph",
                "content": [{"type": "text", "text": "a < b & c > d"}]})
    assert prosemirror_to_html(doc) == "<p>a &lt; b &amp; c &gt; d</p>"


def test_unknown_node_renders_children_not_dropped():
    doc = _doc({"type": "weirdBlock", "content": [
        {"type": "paragraph", "content": [{"type": "text", "text": "keep me"}]}]})
    assert prosemirror_to_html(doc) == "<p>keep me</p>"


def test_empty_and_unparseable_return_none():
    assert prosemirror_to_html(None) is None
    assert prosemirror_to_html("") is None
    assert prosemirror_to_html("   ") is None
    assert prosemirror_to_html("{not json") is None
    assert prosemirror_to_html(json.dumps({"type": "doc", "content": []})) is None


def test_post_body_html_prefers_legacy_content():
    attrs = {"content": "<p>legacy</p>",
             "content_json_string": _doc({"type": "paragraph",
                                          "content": [{"type": "text", "text": "new"}]})}
    assert post_body_html(attrs) == "<p>legacy</p>"


def test_post_body_html_falls_back_to_json_string():
    attrs = {"content": None,
             "content_json_string": _doc({"type": "paragraph",
                                          "content": [{"type": "text", "text": "new"}]})}
    assert post_body_html(attrs) == "<p>new</p>"


def test_post_body_html_none_when_both_empty():
    assert post_body_html({"content": None, "content_json_string": None}) is None
    assert post_body_html({}) is None
    assert post_body_html(None) is None
