import pytest
from pypugjs.lexer import Lexer
from pypugjs.utils import odict

expected_results = {
    "p Here is some #[strong: em text] and look at #[a(href='https://google.com') this link!]": [
        {"buffer": None, "line": 1, "type": "tag", "inline_level": 0, "val": "p"},
        {
            "buffer": None,
            "line": 1,
            "type": "string",
            "inline_level": 0,
            "val": "Here is some ",
        },
        {"buffer": None, "type": "tag", "line": 1, "inline_level": 1, "val": "strong"},
        {"buffer": None, "type": ":", "line": 1, "inline_level": 1, "val": None},
        {"buffer": None, "type": "tag", "line": 1, "inline_level": 1, "val": "em"},
        {"buffer": None, "type": "text", "line": 1, "inline_level": 1, "val": " text"},
        {
            "buffer": None,
            "line": 1,
            "type": "string",
            "inline_level": 0,
            "val": " and look at ",
        },
        {"buffer": None, "inline_level": 1, "line": 1, "type": "tag", "val": "a"},
        {
            "inline_level": 1,
            "val": None,
            "buffer": None,
            "static_attrs": set(["href"]),
            "attrs": odict([("href", "'https://google.com'")]),
            "line": 1,
            "type": "attrs",
        },
        {
            "buffer": None,
            "inline_level": 1,
            "line": 1,
            "type": "text",
            "val": " this link!",
        },
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
    ],
    "p Other inline #[strong= 'test']": [
        {"buffer": None, "line": 1, "type": "tag", "inline_level": 0, "val": "p"},
        {
            "buffer": None,
            "line": 1,
            "type": "string",
            "inline_level": 0,
            "val": "Other inline ",
        },
        {"buffer": None, "type": "tag", "line": 1, "inline_level": 1, "val": "strong"},
        {
            "inline_level": 1,
            "val": " 'test'",
            "buffer": True,
            "escape": True,
            "line": 1,
            "type": "code",
        },
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
    ],
    "p Test #[|text line]": [
        {"buffer": None, "line": 1, "type": "tag", "inline_level": 0, "val": "p"},
        {
            "buffer": None,
            "line": 1,
            "type": "string",
            "inline_level": 0,
            "val": "Test ",
        },
        {
            "buffer": None,
            "type": "string",
            "line": 1,
            "inline_level": 1,
            "val": "text line",
        },
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
    ],
    "p Test buffered #[= map(str, zip('iln', 'nie')) + 'code']": [
        {"buffer": None, "line": 1, "type": "tag", "inline_level": 0, "val": "p"},
        {
            "buffer": None,
            "line": 1,
            "type": "string",
            "inline_level": 0,
            "val": "Test buffered ",
        },
        {
            "inline_level": 1,
            "val": " map(str, zip('iln', 'nie')) + 'code'",
            "buffer": True,
            "escape": True,
            "line": 1,
            "type": "code",
        },
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
    ],
    "p #[- abcf = [[123, [[],[]], []],'abc']] #[= abcf]": [
        {"buffer": None, "line": 1, "type": "tag", "inline_level": 0, "val": "p"},
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
        {
            "inline_level": 1,
            "val": " abcf = [[123, [[],[]], []],'abc']",
            "buffer": False,
            "escape": False,
            "line": 1,
            "type": "code",
        },
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": " "},
        {
            "inline_level": 1,
            "val": " abcf",
            "buffer": True,
            "escape": True,
            "line": 1,
            "type": "code",
        },
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
    ],
    "#[#[#[a a#[b #[i a] b]] d]e]": [
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
        {"buffer": None, "type": "string", "line": 1, "inline_level": 1, "val": ""},
        {"buffer": None, "type": "string", "line": 1, "inline_level": 2, "val": ""},
        {"buffer": None, "type": "tag", "line": 1, "inline_level": 3, "val": "a"},
        {"buffer": None, "type": "string", "line": 1, "inline_level": 3, "val": "a"},
        {"buffer": None, "type": "tag", "line": 1, "inline_level": 4, "val": "b"},
        {"buffer": None, "type": "string", "line": 1, "inline_level": 4, "val": ""},
        {"buffer": None, "type": "tag", "line": 1, "inline_level": 5, "val": "i"},
        {"buffer": None, "type": "text", "line": 1, "inline_level": 5, "val": " a"},
        {"buffer": None, "type": "string", "line": 1, "inline_level": 4, "val": " b"},
        {"buffer": None, "type": "string", "line": 1, "inline_level": 3, "val": ""},
        {"buffer": None, "type": "string", "line": 1, "inline_level": 2, "val": " d"},
        {"buffer": None, "type": "string", "line": 1, "inline_level": 1, "val": "e"},
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
    ],
    "p We can also #[strong combine #[em multiple #[img(src='https://jade-lang.com/style/logo.png')]]]": [
        {"buffer": None, "line": 1, "type": "tag", "inline_level": 0, "val": "p"},
        {
            "buffer": None,
            "line": 1,
            "type": "string",
            "inline_level": 0,
            "val": "We can also ",
        },
        {"buffer": None, "type": "tag", "line": 1, "inline_level": 1, "val": "strong"},
        {
            "buffer": None,
            "type": "string",
            "line": 1,
            "inline_level": 1,
            "val": "combine ",
        },
        {"buffer": None, "type": "tag", "line": 1, "inline_level": 2, "val": "em"},
        {
            "buffer": None,
            "type": "string",
            "line": 1,
            "inline_level": 2,
            "val": "multiple ",
        },
        {"buffer": None, "type": "tag", "line": 1, "inline_level": 3, "val": "img"},
        {
            "inline_level": 3,
            "val": None,
            "buffer": None,
            "static_attrs": {"src"},
            "attrs": odict([("src", "'https://jade-lang.com/style/logo.png'")]),
            "line": 1,
            "type": "attrs",
        },
        {"buffer": None, "type": "string", "line": 1, "inline_level": 2, "val": ""},
        {"buffer": None, "type": "string", "line": 1, "inline_level": 1, "val": ""},
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
    ],
    r"#[strong start] line with #[i]\#[j] inline": [
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
        {"buffer": None, "type": "tag", "line": 1, "inline_level": 1, "val": "strong"},
        {
            "buffer": None,
            "type": "text",
            "line": 1,
            "inline_level": 1,
            "val": " start",
        },
        {
            "buffer": None,
            "line": 1,
            "type": "string",
            "inline_level": 0,
            "val": " line with ",
        },
        {"buffer": None, "type": "tag", "line": 1, "inline_level": 1, "val": "i"},
        {
            "buffer": None,
            "line": 1,
            "type": "string",
            "inline_level": 0,
            "val": "#[j] inline",
        },
    ],
    "p Another #[strong.lil#okf(acs=[1,2]) test [[with brackets]] [in#[='side']]]": [
        {"buffer": None, "line": 1, "type": "tag", "inline_level": 0, "val": "p"},
        {
            "buffer": None,
            "line": 1,
            "type": "string",
            "inline_level": 0,
            "val": "Another ",
        },
        {"buffer": None, "type": "tag", "line": 1, "inline_level": 1, "val": "strong"},
        {"buffer": None, "type": "class", "line": 1, "inline_level": 1, "val": "lil"},
        {"buffer": None, "type": "id", "line": 1, "inline_level": 1, "val": "okf"},
        {
            "val": None,
            "buffer": None,
            "static_attrs": set([]),
            "attrs": odict([("acs", "[1,2]")]),
            "line": 1,
            "type": "attrs",
            "inline_level": 1,
        },
        {
            "buffer": None,
            "type": "string",
            "line": 1,
            "inline_level": 1,
            "val": "test [[with brackets]] [in",
        },
        {
            "inline_level": 2,
            "val": "'side'",
            "buffer": True,
            "escape": True,
            "line": 1,
            "type": "code",
        },
        {"buffer": None, "type": "string", "line": 1, "inline_level": 1, "val": "]"},
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
    ],
    """mixin lala(a, b)
  span lala(#{a}, #{b})
p Test inline mixin #[+lala(123, 'lala inside inline')] end""": [
        {
            "args": "a, b",
            "buffer": None,
            "line": 1,
            "type": "mixin",
            "inline_level": 0,
            "val": "lala",
        },
        {"buffer": None, "line": 2, "type": "indent", "inline_level": 0, "val": 2},
        {"buffer": None, "line": 2, "type": "tag", "inline_level": 0, "val": "span"},
        {
            "buffer": None,
            "line": 2,
            "type": "text",
            "inline_level": 0,
            "val": " lala(#{a}, #{b})",
        },
        {"buffer": None, "line": 3, "type": "outdent", "inline_level": 0, "val": None},
        {"buffer": None, "line": 3, "type": "tag", "inline_level": 0, "val": "p"},
        {
            "buffer": None,
            "line": 3,
            "type": "string",
            "inline_level": 0,
            "val": "Test inline mixin ",
        },
        {
            "inline_level": 1,
            "val": "lala",
            "buffer": None,
            "args": "123, 'lala inside inline'",
            "line": 1,
            "type": "call",
        },
        {
            "buffer": None,
            "line": 3,
            "type": "string",
            "inline_level": 0,
            "val": " end",
        },
    ],
    "p only class #[.strong: em inline]": [
        {"buffer": None, "line": 1, "type": "tag", "inline_level": 0, "val": "p"},
        {
            "buffer": None,
            "line": 1,
            "type": "string",
            "inline_level": 0,
            "val": "only class ",
        },
        {
            "buffer": None,
            "inline_level": 1,
            "line": 1,
            "type": "class",
            "val": "strong",
        },
        {"buffer": None, "inline_level": 1, "line": 1, "type": ":", "val": None},
        {"buffer": None, "inline_level": 1, "line": 1, "type": "tag", "val": "em"},
        {
            "buffer": None,
            "inline_level": 1,
            "line": 1,
            "type": "text",
            "val": " inline",
        },
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
    ],
    "#[asdf.lol(fff)#[asdf]]": [
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
        {"buffer": None, "inline_level": 1, "line": 1, "type": "tag", "val": "asdf"},
        {"buffer": None, "inline_level": 1, "line": 1, "type": "class", "val": "lol"},
        {
            "inline_level": 1,
            "val": None,
            "buffer": None,
            "static_attrs": set(["fff"]),
            "attrs": odict([("fff", True)]),
            "line": 1,
            "type": "attrs",
        },
        {"buffer": None, "inline_level": 1, "line": 1, "type": "string", "val": ""},
        {"buffer": None, "inline_level": 2, "line": 1, "type": "tag", "val": "asdf"},
        {"buffer": None, "inline_level": 1, "line": 1, "type": "string", "val": ""},
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
    ],
    "#[= '[[[[[[[[[[']": [
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
        {
            "buffer": True,
            "line": 1,
            "type": "code",
            "val": " '[[[[[[[[[['",
            "escape": True,
            "inline_level": 1,
        },
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
    ],
    "#[= ']]]]]]]]]]']": [
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
        {
            "buffer": True,
            "line": 1,
            "type": "code",
            "val": " ']]]]]]]]]]'",
            "escape": True,
            "inline_level": 1,
        },
        {"buffer": None, "line": 1, "type": "string", "inline_level": 0, "val": ""},
    ],
}


def generate_expected(pugjs):
    lx = Lexer(pugjs)
    res = []
    while True:
        tok = lx.advance()
        if tok.type == "eos":
            break
        res.append(tok.__dict__)
    return res


@pytest.mark.parametrize("key", expected_results.keys())
def test_lexer(key):
    result = generate_expected(key)
    assert expected_results[key] == result, key
