# -*- coding: utf-8 -*-
"""
Python Markdown

A Python implementation of John Gruber's Markdown.

Documentation: https://python-markdown.github.io/
GitHub: https://github.com/Python-Markdown/markdown/
PyPI: https://pypi.org/project/Markdown/

Started by Manfred Stienstra (http://www.dwerg.net/).
Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
Currently maintained by Waylan Limberg (https://github.com/waylan),
Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).

Copyright 2007-2023 The Python Markdown Project (v. 1.7 and later)
Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
Copyright 2004 Manfred Stienstra (the original version)

License: BSD (see LICENSE.md for details).
"""

from unittest import TestSuite
from markdown.test_tools import TestCase
from ..blocks.test_html_blocks import TestHTMLBlocks
from markdown import Markdown
from xml.etree.ElementTree import Element


class TestMarkdownInHTMLPostProcessor(TestCase):
    """ Ensure any remaining elements in HTML stash are properly serialized. """

    def test_stash_to_string(self):
        # There should be no known cases where this actually happens so we need to
        # forcefully pass an `etree` `Element` to the method to ensure proper behavior.
        element = Element('div')
        element.text = 'Foo bar.'
        md = Markdown(extensions=['md_in_html'])
        result = md.postprocessors['raw_html'].stash_to_string(element)
        self.assertEqual(result, '<div>Foo bar.</div>')


class TestDefaultwMdInHTML(TestHTMLBlocks):
    """ Ensure the md_in_html extension does not break the default behavior. """

    default_kwargs = {'extensions': ['md_in_html']}


class TestMdInHTML(TestCase):

    default_kwargs = {'extensions': ['md_in_html']}

    def test_md1_paragraph(self):
        self.assertMarkdownRenders(
            '<p markdown="1">*foo*</p>',
            '<p><em>foo</em></p>'
        )

    def test_md1_p_linebreaks(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <p markdown="1">
                *foo*
                </p>
                """
            ),
            self.dedent(
                """
                <p>
                <em>foo</em>
                </p>
                """
            )
        )

    def test_md1_p_blank_lines(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <p markdown="1">

                *foo*

                </p>
                """
            ),
            self.dedent(
                """
                <p>

                <em>foo</em>

                </p>
                """
            )
        )

    def test_md1_div(self):
        self.assertMarkdownRenders(
            '<div markdown="1">*foo*</div>',
            self.dedent(
                """
                <div>
                <p><em>foo</em></p>
                </div>
                """
            )
        )

    def test_md1_div_linebreaks(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                *foo*
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p><em>foo</em></p>
                </div>
                """
            )
        )

    def test_md1_code_span(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                `<h1>code span</h1>`
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p><code>&lt;h1&gt;code span&lt;/h1&gt;</code></p>
                </div>
                """
            )
        )

    def test_md1_code_span_oneline(self):
        self.assertMarkdownRenders(
            '<div markdown="1">`<h1>code span</h1>`</div>',
            self.dedent(
                """
                <div>
                <p><code>&lt;h1&gt;code span&lt;/h1&gt;</code></p>
                </div>
                """
            )
        )

    def test_md1_code_span_unclosed(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                `<p>`
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p><code>&lt;p&gt;</code></p>
                </div>
                """
            )
        )

    def test_md1_code_span_script_tag(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                `<script>`
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p><code>&lt;script&gt;</code></p>
                </div>
                """
            )
        )

    def test_md1_div_blank_lines(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">

                *foo*

                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p><em>foo</em></p>
                </div>
                """
            )
        )

    def test_md1_div_multi(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">

                *foo*

                __bar__

                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p><em>foo</em></p>
                <p><strong>bar</strong></p>
                </div>
                """
            )
        )

    def test_md1_div_nested(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">

                <div markdown="1">
                *foo*
                </div>

                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <div>
                <p><em>foo</em></p>
                </div>
                </div>
                """
            )
        )

    def test_md1_div_multi_nest(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">

                <div markdown="1">
                <p markdown="1">*foo*</p>
                </div>

                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <div>
                <p><em>foo</em></p>
                </div>
                </div>
                """
            )
        )

    def text_md1_details(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <details markdown="1">
                <summary>Click to expand</summary>
                *foo*
                </details>
                """
            ),
            self.dedent(
                """
                <details>
                <summary>Click to expand</summary>
                <p><em>foo</em></p>
                </details>
                """
            )
        )

    def test_md1_mix(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                A _Markdown_ paragraph before a raw child.

                <p markdown="1">A *raw* child.</p>

                A _Markdown_ tail to the raw child.
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p>A <em>Markdown</em> paragraph before a raw child.</p>
                <p>A <em>raw</em> child.</p>
                <p>A <em>Markdown</em> tail to the raw child.</p>
                </div>
                """
            )
        )

    def test_md1_deep_mix(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">

                A _Markdown_ paragraph before a raw child.

                A second Markdown paragraph
                with two lines.

                <div markdown="1">

                A *raw* child.

                <p markdown="1">*foo*</p>

                Raw child tail.

                </div>

                A _Markdown_ tail to the raw child.

                A second tail item
                with two lines.

                <p markdown="1">More raw.</p>

                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p>A <em>Markdown</em> paragraph before a raw child.</p>
                <p>A second Markdown paragraph
                with two lines.</p>
                <div>
                <p>A <em>raw</em> child.</p>
                <p><em>foo</em></p>
                <p>Raw child tail.</p>
                </div>
                <p>A <em>Markdown</em> tail to the raw child.</p>
                <p>A second tail item
                with two lines.</p>
                <p>More raw.</p>
                </div>
                """
            )
        )

    def test_md1_div_raw_inline(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">

                <em>foo</em>

                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p><em>foo</em></p>
                </div>
                """
            )
        )

    def test_no_md1_paragraph(self):
        self.assertMarkdownRenders(
            '<p>*foo*</p>',
            '<p>*foo*</p>'
        )

    def test_no_md1_nest(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                A _Markdown_ paragraph before a raw child.

                <p>A *raw* child.</p>

                A _Markdown_ tail to the raw child.
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p>A <em>Markdown</em> paragraph before a raw child.</p>
                <p>A *raw* child.</p>
                <p>A <em>Markdown</em> tail to the raw child.</p>
                </div>
                """
            )
        )

    def test_md1_nested_empty(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                A _Markdown_ paragraph before a raw empty tag.

                <img src="image.png" alt="An image" />

                A _Markdown_ tail to the raw empty tag.
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p>A <em>Markdown</em> paragraph before a raw empty tag.</p>
                <p><img src="image.png" alt="An image" /></p>
                <p>A <em>Markdown</em> tail to the raw empty tag.</p>
                </div>
                """
            )
        )

    def test_md1_nested_empty_block(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                A _Markdown_ paragraph before a raw empty tag.

                <hr />

                A _Markdown_ tail to the raw empty tag.
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p>A <em>Markdown</em> paragraph before a raw empty tag.</p>
                <hr />
                <p>A <em>Markdown</em> tail to the raw empty tag.</p>
                </div>
                """
            )
        )

    def test_empty_tags(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                <div></div>
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <div></div>
                </div>
                """
            )
        )

    def test_orphan_end_tag_in_raw_html(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                <div>
                Test

                </pre>

                Test
                </div>
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <div>
                Test

                </pre>

                Test
                </div>
                </div>
                """
            )
        )

    def test_complex_nested_case(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                **test**
                <div>
                **test**
                <img src=""/>
                <code>Test</code>
                <span>**test**</span>
                <p>Test 2</p>
                </div>
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p><strong>test</strong></p>
                <div>
                **test**
                <img src=""/>
                <code>Test</code>
                <span>**test**</span>
                <p>Test 2</p>
                </div>
                </div>
                """
            )
        )

    def test_complex_nested_case_whitespace(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                Text with space\t
                <div markdown="1">\t
                \t
                 <div>
                **test**
                <img src=""/>
                <code>Test</code>
                <span>**test**</span>
                  <div>With whitespace</div>
                <p>Test 2</p>
                </div>
                **test**
                </div>
                """
            ),
            self.dedent(
                """
                <p>Text with space </p>
                <div>
                <div>
                **test**
                <img src=""/>
                <code>Test</code>
                <span>**test**</span>
                  <div>With whitespace</div>
                <p>Test 2</p>
                </div>
                <p><strong>test</strong></p>
                </div>
                """
            )
        )

    def test_md1_intail_md1(self):
        self.assertMarkdownRenders(
            '<div markdown="1">*foo*</div><div markdown="1">*bar*</div>',
            self.dedent(
                """
                <div>
                <p><em>foo</em></p>
                </div>
                <div>
                <p><em>bar</em></p>
                </div>
                """
            )
        )

    def test_md1_no_blank_line_before(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                A _Markdown_ paragraph with no blank line after.
                <div markdown="1">
                A _Markdown_ paragraph in an HTML block with no blank line before.
                </div>
                """
            ),
            self.dedent(
                """
                <p>A <em>Markdown</em> paragraph with no blank line after.</p>
                <div>
                <p>A <em>Markdown</em> paragraph in an HTML block with no blank line before.</p>
                </div>
                """
            )
        )

    def test_md1_no_line_break(self):
        # The div here is parsed as a span-level element. Bad input equals bad output!
        self.assertMarkdownRenders(
            'A _Markdown_ paragraph with <div markdown="1">no _line break_.</div>',
            '<p>A <em>Markdown</em> paragraph with <div markdown="1">no <em>line break</em>.</div></p>'
        )

    def test_md1_in_tail(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div></div><div markdown="1">
                A _Markdown_ paragraph in an HTML block in tail of previous element.
                </div>
                """
            ),
            self.dedent(
                """
                <div></div>
                <div>
                <p>A <em>Markdown</em> paragraph in an HTML block in tail of previous element.</p>
                </div>
                """
            )
        )

    def test_md1_PI_oneliner(self):
        self.assertMarkdownRenders(
            '<div markdown="1"><?php print("foo"); ?></div>',
            self.dedent(
                """
                <div>
                <?php print("foo"); ?>
                </div>
                """
            )
        )

    def test_md1_PI_multiline(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                <?php print("foo"); ?>
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <?php print("foo"); ?>
                </div>
                """
            )
        )

    def test_md1_PI_blank_lines(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">

                <?php print("foo"); ?>

                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <?php print("foo"); ?>
                </div>
                """
            )
        )

    def test_md_span_paragraph(self):
        self.assertMarkdownRenders(
            '<p markdown="span">*foo*</p>',
            '<p><em>foo</em></p>'
        )

    def test_md_block_paragraph(self):
        self.assertMarkdownRenders(
            '<p markdown="block">*foo*</p>',
            self.dedent(
                """
                <p>
                <p><em>foo</em></p>
                </p>
                """
            )
        )

    def test_md_span_div(self):
        self.assertMarkdownRenders(
            '<div markdown="span">*foo*</div>',
            '<div><em>foo</em></div>'
        )

    def test_md_block_div(self):
        self.assertMarkdownRenders(
            '<div markdown="block">*foo*</div>',
            self.dedent(
                """
                <div>
                <p><em>foo</em></p>
                </div>
                """
            )
        )

    def test_md_span_nested_in_block(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="block">
                <div markdown="span">*foo*</div>
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <div><em>foo</em></div>
                </div>
                """
            )
        )

    def test_md_block_nested_in_span(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="span">
                <div markdown="block">*foo*</div>
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <div><em>foo</em></div>
                </div>
                """
            )
        )

    def test_md_block_after_span_nested_in_block(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="block">
                <div markdown="span">*foo*</div>
                <div markdown="block">*bar*</div>
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <div><em>foo</em></div>
                <div>
                <p><em>bar</em></p>
                </div>
                </div>
                """
            )
        )

    def test_nomd_nested_in_md1(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                *foo*
                <div>
                *foo*
                <p>*bar*</p>
                *baz*
                </div>
                *bar*
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p><em>foo</em></p>
                <div>
                *foo*
                <p>*bar*</p>
                *baz*
                </div>
                <p><em>bar</em></p>
                </div>
                """
            )
        )

    def test_md1_nested_in_nomd(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div>
                <div markdown="1">*foo*</div>
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <div markdown="1">*foo*</div>
                </div>
                """
            )
        )

    def test_md1_single_quotes(self):
        self.assertMarkdownRenders(
            "<p markdown='1'>*foo*</p>",
            '<p><em>foo</em></p>'
        )

    def test_md1_no_quotes(self):
        self.assertMarkdownRenders(
            '<p markdown=1>*foo*</p>',
            '<p><em>foo</em></p>'
        )

    def test_md_no_value(self):
        self.assertMarkdownRenders(
            '<p markdown>*foo*</p>',
            '<p><em>foo</em></p>'
        )

    def test_md1_preserve_attrs(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1" id="parent">

                <div markdown="1" class="foo">
                <p markdown="1" class="bar baz">*foo*</p>
                </div>

                </div>
                """
            ),
            self.dedent(
                """
                <div id="parent">
                <div class="foo">
                <p class="bar baz"><em>foo</em></p>
                </div>
                </div>
                """
            )
        )

    def test_md1_unclosed_div(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">

                _foo_

                <div class="unclosed">

                _bar_

                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p><em>foo</em></p>
                <div class="unclosed">

                _bar_

                </div>
                </div>
                """
            )
        )

    def test_md1_orphan_endtag(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">

                _foo_

                </p>

                _bar_

                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p><em>foo</em></p>
                </p>
                <p><em>bar</em></p>
                </div>
                """
            )
        )

    def test_md1_unclosed_p(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <p markdown="1">_foo_
                <p markdown="1">_bar_
                """
            ),
            self.dedent(
                """
                <p><em>foo</em>
                </p>
                <p><em>bar</em>

                </p>
                """
            )
        )

    def test_md1_nested_unclosed_p(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                <p markdown="1">_foo_
                <p markdown="1">_bar_
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p><em>foo</em>
                </p>
                <p><em>bar</em>
                </p>
                </div>
                """
            )
        )

    def test_md1_nested_comment(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                A *Markdown* paragraph.
                <!-- foobar -->
                A *Markdown* paragraph.
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <p>A <em>Markdown</em> paragraph.</p>
                <!-- foobar -->
                <p>A <em>Markdown</em> paragraph.</p>
                </div>
                """
            )
        )

    def test_md1_nested_link_ref(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                [link]: http://example.com
                <div markdown="1">
                [link][link]
                </div>
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <div>
                <p><a href="http://example.com">link</a></p>
                </div>
                </div>
                """
            )
        )

    def test_md1_hr_only_start(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                *emphasis1*
                <hr markdown="1">
                *emphasis2*
                """
            ),
            self.dedent(
                """
                <p><em>emphasis1</em></p>
                <hr>
                <p><em>emphasis2</em></p>
                """
            )
        )

    def test_md1_hr_self_close(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                *emphasis1*
                <hr markdown="1" />
                *emphasis2*
                """
            ),
            self.dedent(
                """
                <p><em>emphasis1</em></p>
                <hr>
                <p><em>emphasis2</em></p>
                """
            )
        )

    def test_md1_hr_start_and_end(self):
        # Browsers ignore ending hr tags, so we don't try to do anything to handle them special.
        self.assertMarkdownRenders(
            self.dedent(
                """
                *emphasis1*
                <hr markdown="1"></hr>
                *emphasis2*
                """
            ),
            self.dedent(
                """
                <p><em>emphasis1</em></p>
                <hr>
                <p></hr>
                <em>emphasis2</em></p>
                """
            )
        )

    def test_md1_hr_only_end(self):
        # Browsers ignore ending hr tags, so we don't try to do anything to handle them special.
        self.assertMarkdownRenders(
            self.dedent(
                """
                *emphasis1*
                </hr>
                *emphasis2*
                """
            ),
            self.dedent(
                """
                <p><em>emphasis1</em>
                </hr>
                <em>emphasis2</em></p>
                """
            )
        )

    def test_md1_hr_with_content(self):
        # Browsers ignore ending hr tags, so we don't try to do anything to handle them special.
        # Content is not allowed and will be treated as normal content between two hr tags
        self.assertMarkdownRenders(
            self.dedent(
                """
                *emphasis1*
                <hr markdown="1">
                **content**
                </hr>
                *emphasis2*
                """
            ),
            self.dedent(
                """
                <p><em>emphasis1</em></p>
                <hr>
                <p><strong>content</strong>
                </hr>
                <em>emphasis2</em></p>
                """
            )
        )

    def test_no_md1_hr_with_content(self):
        # Browsers ignore ending hr tags, so we don't try to do anything to handle them special.
        # Content is not allowed and will be treated as normal content between two hr tags
        self.assertMarkdownRenders(
            self.dedent(
                """
                *emphasis1*
                <hr>
                **content**
                </hr>
                *emphasis2*
                """
            ),
            self.dedent(
                """
                <p><em>emphasis1</em></p>
                <hr>
                <p><strong>content</strong>
                </hr>
                <em>emphasis2</em></p>
                """
            )
        )

    def test_md1_nested_abbr_ref(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                *[abbr]: Abbreviation
                <div markdown="1">
                abbr
                </div>
                </div>
                """
            ),
            self.dedent(
                """
                <div>
                <div>
                <p><abbr title="Abbreviation">abbr</abbr></p>
                </div>
                </div>
                """
            ),
            extensions=['md_in_html', 'abbr']
        )

    def test_md1_nested_footnote_ref(self):
        self.assertMarkdownRenders(
            self.dedent(
                """
                <div markdown="1">
                [^1]: The footnote.
                <div markdown="1">
                Paragraph with a footnote.[^1]
                </div>
                </div>
                """
            ),
            '<div>\n'
            '<div>\n'
            '<p>Paragraph with a footnote.<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p>\n'
            '</div>\n'
            '</div>\n'
            '<div class="footnote">\n'
            '<hr />\n'
            '<ol>\n'
            '<li id="fn:1">\n'
            '<p>The footnote.&#160;'
            '<a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a>'
            '</p>\n'
            '</li>\n'
            '</ol>\n'
            '</div>',
            extensions=['md_in_html', 'footnotes']
        )


def load_tests(loader, tests, pattern):
    """ Ensure `TestHTMLBlocks` doesn't get run twice by excluding it here. """
    suite = TestSuite()
    for test_class in [TestDefaultwMdInHTML, TestMdInHTML, TestMarkdownInHTMLPostProcessor]:
        tests = loader.loadTestsFromTestCase(test_class)
        suite.addTests(tests)
    return suite
