import pytest

from ate.ate import Template, ParseContext
from ate.tags import CompileStatement
from ate.tags import TextNode
from ate.tags import ExpressionNode
from ate.tags import BlockStatementNode
from ate.tags import MainNode
from ate.tags import ForBlockStatementNode
from ate.tags import CommentNode

from ate.tags import parse_expression
from ate.exceptions import ExpressionNotClosed


class TestMyTpl:

    def test_empty(self):
        template = Template("")
        assert isinstance(template.mainnode, MainNode)
        assert len(template.mainnode.nodes) == 0

    def test_multiline(self):
        tpl = """Hello
        world

        bye!"""
        template = Template(tpl)
        assert isinstance(template.mainnode, MainNode)
        assert isinstance(template.mainnode.nodes[0], TextNode)
        assert template.mainnode.nodes[0].text == tpl

    def test_statement(self):
        tpl = "{{hello}}"
        res, skip = CompileStatement(ParseContext(tpl))
        assert skip == len(tpl)
        assert isinstance(res, ExpressionNode)
        assert res.expression == "hello"

    def test_block(self):
        tpl = "{% for i in abc%} x {% endfor %}"
        res, skip = CompileStatement(ParseContext(tpl))
        assert skip == len(tpl)
        assert isinstance(res, BlockStatementNode)
        assert res.type == "for"
        assert res.expression == "i in abc"
        assert res.code == tpl

        assert len(res.nodes) == 1
        assert isinstance(res.nodes[0], TextNode)
        assert res.nodes[0].text == " x "

    def test_complex(self):
        tpl = """Hello World

        {% for i in abc%}
          x {{i}}
        {% endfor %}

        That's all!"""
        t = Template(tpl)
        assert len(t.mainnode.nodes) == 3
        nodes = t.mainnode.nodes
        assert isinstance(nodes[0], TextNode)
        assert isinstance(nodes[1], BlockStatementNode)
        assert isinstance(nodes[2], TextNode)

    def test_closing_spacing(self):
        tn = ForBlockStatementNode("for")
        index = tn.compile(ParseContext("{%for%}{%endfor%}"), len("{%for%}"))
        assert index == 17

    def test_closing_spacing2(self):
        tn = ForBlockStatementNode("for")
        index = tn.compile(ParseContext("{%for%}{% endfor%}"), len("{%for%}"))
        assert index == 18

    def test_closing_spacing3(self):
        tn = ForBlockStatementNode("for")
        index = tn.compile(ParseContext("{%for%}{%  endfor%}"), len("{%for%}"))
        assert index == 19

    def test_closing_spacing4(self):
        tn = ForBlockStatementNode("for")
        index = tn.compile(ParseContext("{%for%}{%endfor %}"), len("{%for%}"))
        assert index == 18

    def test_closing_spacing5(self):
        tn = ForBlockStatementNode("for")
        index = tn.compile(ParseContext("{%for%}{%endfor  %}"), len("{%for%}"))
        assert index == 19

    def test_closing_spacing6(self):
        tn = ForBlockStatementNode("for")
        index = tn.compile(ParseContext(
            "{%for%}{%  endfor  %}"), len("{%for%}"))
        assert index == 21

    def test_close_marker_in_expr(self):
        tpl = "{% for i in '%}' %} x {% endfor %}"
        res, skip = CompileStatement(ParseContext(tpl))
        assert res.expression == "i in '%}'"

    def test_comment_simple(self):
        tpl = "{# hello world #}"
        res, skip = CompileStatement(ParseContext(tpl))
        assert isinstance(res, CommentNode)
        assert res.expression == " hello world "

    def test_comment_broken_statement(self):
        tpl = "{# {% for #}"
        res, skip = CompileStatement(ParseContext(tpl))
        assert isinstance(res, CommentNode)
        assert res.expression == " {% for "

    def test_comment_statement(self):
        tpl = """{# {% for i in '123' %}
{{i}}
{%endfor%} #}"""
        res, skip = CompileStatement(ParseContext(tpl))
        assert isinstance(res, CommentNode)
        assert res.expression == """ {% for i in '123' %}
{{i}}
{%endfor%} """

    def test_comment_expression(self):
        tpl = "{# {{'hello'}} #}"
        res, skip = CompileStatement(ParseContext(tpl))
        assert isinstance(res, CommentNode)
        assert res.expression == " {{'hello'}} "

    def test_css(self):
        tpl = """<html>
<style>
  p, th, td {
    font-family: 'Open Sans', sans-serif;
  }</style>
</html>
"""
        template = Template(tpl)
        assert isinstance(template.mainnode, MainNode)
        assert isinstance(template.mainnode.nodes[0], TextNode)
        assert template.mainnode.nodes[0].text == tpl

    def test_accolade(self):
        tpl = """if {} { {! {% for i in '123' %}{{i}}{%endfor%} { }} {="""
        template = Template(tpl)
        assert isinstance(template.mainnode.nodes[0], TextNode)
        assert template.mainnode.nodes[0].text == "if {} { {! "
        assert isinstance(template.mainnode.nodes[1], ForBlockStatementNode)
        assert isinstance(template.mainnode.nodes[2], TextNode)
        assert template.mainnode.nodes[2].text == " { }} {="


class TestTemplateRender:

    def test_render_text(self):
        tpl = Template("Hello World\n"
                       "\n"
                       "{% for i in abc%}\n"
                       "  x {{i}}\n"
                       "{% endfor %}\n"
                       "\n"
                       "That's all!")
        rendered = tpl.render_nested(i=1, abc=[1])
        assert rendered[0] == "Hello World\n\n"
        assert rendered[1][0] == "\n  x "
        assert rendered[1][2] == "\n"
        assert rendered[2] == "\n\nThat's all!"


class TestStatementEval:

    def test_interpolation(self):
        tpl = Template("{{i}}")
        assert tpl.render(i=10) == "10"
        assert tpl.render(i=0) == "0"
        assert tpl.render(i=-10) == "-10"
        assert tpl.render(i="hello") == "hello"

    def test_expression(self):
        tpl = Template("{{i + j}}")
        assert tpl.render(i=10, j=5) == "15"