import pytest
from webdriver.bidi.modules.script import ContextTarget, SerializationOptions

from ... import any_string, recursive_compare

pytestmark = pytest.mark.asyncio


@pytest.mark.parametrize(
    "include_shadow_tree, shadow_root_mode, contains_children, expected",
    [
        (
            None,
            "open",
            False,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {"nodeType": 11, "childNodeCount": 1},
            },
        ),
        (
            None,
            "closed",
            False,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {"nodeType": 11, "childNodeCount": 1},
            },
        ),
        (
            "none",
            "open",
            False,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {"nodeType": 11, "childNodeCount": 1},
            },
        ),
        (
            "none",
            "closed",
            False,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {"nodeType": 11, "childNodeCount": 1},
            },
        ),
        (
            "open",
            "open",
            True,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {
                    "nodeType": 11,
                    "childNodeCount": 1,
                    "children": [
                        {
                            "type": "node",
                            "sharedId": any_string,
                            "value": {
                                "nodeType": 1,
                                "localName": "div",
                                "namespaceURI": "http://www.w3.org/1999/xhtml",
                                "childNodeCount": 1,
                                "attributes": {"id": "in-shadow-dom"},
                                "shadowRoot": None,
                            },
                        }
                    ],
                    "mode": "open",
                },
            },
        ),
        (
            "open",
            "closed",
            False,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {"nodeType": 11, "childNodeCount": 1},
            },
        ),
        (
            "all",
            "open",
            True,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {
                    "nodeType": 11,
                    "childNodeCount": 1,
                    "children": [
                        {
                            "type": "node",
                            "sharedId": any_string,
                            "value": {
                                "nodeType": 1,
                                "localName": "div",
                                "namespaceURI": "http://www.w3.org/1999/xhtml",
                                "childNodeCount": 1,
                                "attributes": {"id": "in-shadow-dom"},
                                "shadowRoot": None,
                            },
                        }
                    ],
                    "mode": "open",
                },
            },
        ),
        (
            "all",
            "closed",
            True,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {
                    "nodeType": 11,
                    "childNodeCount": 1,
                    "children": [
                        {
                            "type": "node",
                            "sharedId": any_string,
                            "value": {
                                "nodeType": 1,
                                "localName": "div",
                                "namespaceURI": "http://www.w3.org/1999/xhtml",
                                "childNodeCount": 1,
                                "attributes": {"id": "in-shadow-dom"},
                                "shadowRoot": None,
                            },
                        }
                    ],
                    "mode": "closed",
                },
            },
        ),
    ],
    ids=[
        "default mode for open shadow root",
        "default mode for closed shadow root",
        "'none' mode for open shadow root",
        "'none' mode for closed shadow root",
        "'open' mode for open shadow root",
        "'open' mode for closed shadow root",
        "'all' mode for open shadow root",
        "'all' mode for closed shadow root",
    ],
)
async def test_include_shadow_tree_for_custom_element(
    bidi_session,
    top_context,
    get_test_page,
    include_shadow_tree,
    shadow_root_mode,
    contains_children,
    expected
):
    await bidi_session.browsing_context.navigate(
        context=top_context["context"],
        url=get_test_page(shadow_root_mode=shadow_root_mode),
        wait="complete",
    )
    result = await bidi_session.script.evaluate(
        expression="""document.querySelector("custom-element")""",
        target=ContextTarget(top_context["context"]),
        await_promise=True,
        serialization_options=SerializationOptions(
            include_shadow_tree=include_shadow_tree, max_dom_depth=1
        ),
    )

    recursive_compare(expected, result["value"]["shadowRoot"])

    # Explicitely check for children because recursive_compare skips it
    if not contains_children:
        assert "children" not in result["value"]["shadowRoot"]["value"]


@pytest.mark.parametrize(
    "include_shadow_tree, contains_children, expected",
    [
        (
            None,
            False,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {"childNodeCount": 1, "mode": "open", "nodeType": 11},
            },
        ),
        (
            "none",
            False,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {"childNodeCount": 1, "mode": "open", "nodeType": 11},
            },
        ),
        (
            "open",
            True,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {
                    "childNodeCount": 1,
                    "children": [
                        {
                            "type": "node",
                            "sharedId": any_string,
                            "value": {
                                "nodeType": 1,
                                "localName": "div",
                                "namespaceURI": "http://www.w3.org/1999/xhtml",
                                "childNodeCount": 1,
                                "attributes": {"id": "in-shadow-dom"},
                                "shadowRoot": None,
                            },
                        }
                    ],
                    "nodeType": 11,
                    "mode": "open",
                },
            },
        ),
        (
            "all",
            True,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {
                    "childNodeCount": 1,
                    "children": [
                        {
                            "type": "node",
                            "sharedId": any_string,
                            "value": {
                                "nodeType": 1,
                                "localName": "div",
                                "namespaceURI": "http://www.w3.org/1999/xhtml",
                                "childNodeCount": 1,
                                "attributes": {"id": "in-shadow-dom"},
                                "shadowRoot": None,
                            },
                        }
                    ],
                    "mode": "open",
                    "nodeType": 11,
                },
            },
        ),
    ],
    ids=[
        "default mode",
        "'none' mode",
        "'open' mode",
        "'all' mode",
    ],
)
async def test_include_shadow_tree_for_shadow_root(
    bidi_session,
    top_context,
    get_test_page,
    include_shadow_tree,
    contains_children,
    expected
):
    await bidi_session.browsing_context.navigate(
        context=top_context["context"],
        url=get_test_page(),
        wait="complete",
    )
    result = await bidi_session.script.evaluate(
        expression="""document.querySelector("custom-element").shadowRoot""",
        target=ContextTarget(top_context["context"]),
        await_promise=True,
        serialization_options=SerializationOptions(
            include_shadow_tree=include_shadow_tree, max_dom_depth=1
        ),
    )

    recursive_compare(expected, result)

    # Explicitely check for children because recursive_compare skips it
    if not contains_children:
        assert "children" not in result["value"]


@pytest.mark.parametrize(
    "max_dom_depth, expected",
    [
        (
            None,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {
                    "attributes": {"id": "with-children"},
                    "childNodeCount": 2,
                    "localName": "div",
                    "namespaceURI": "http://www.w3.org/1999/xhtml",
                    "nodeType": 1,
                    "shadowRoot": None,
                },
            },
        ),
        (
            0,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {
                    "attributes": {"id": "with-children"},
                    "childNodeCount": 2,
                    "localName": "div",
                    "namespaceURI": "http://www.w3.org/1999/xhtml",
                    "nodeType": 1,
                    "shadowRoot": None,
                },
            },
        ),
        (
            1,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {
                    "attributes": {"id": "with-children"},
                    "childNodeCount": 2,
                    "children": [
                        {
                            "sharedId": any_string,
                            "type": "node",
                            "value": {
                                "attributes": {},
                                "childNodeCount": 1,
                                "localName": "p",
                                "namespaceURI": "http://www.w3.org/1999/xhtml",
                                "nodeType": 1,
                                "shadowRoot": None,
                            },
                        },
                        {
                            "sharedId": any_string,
                            "type": "node",
                            "value": {
                                "attributes": {},
                                "childNodeCount": 0,
                                "localName": "br",
                                "namespaceURI": "http://www.w3.org/1999/xhtml",
                                "nodeType": 1,
                                "shadowRoot": None,
                            },
                        },
                    ],
                    "localName": "div",
                    "namespaceURI": "http://www.w3.org/1999/xhtml",
                    "nodeType": 1,
                    "shadowRoot": None,
                },
            },
        ),
        (
            2,
            {
                "type": "node",
                "sharedId": any_string,
                "value": {
                    "attributes": {"id": "with-children"},
                    "childNodeCount": 2,
                    "children": [
                        {
                            "sharedId": any_string,
                            "type": "node",
                            "value": {
                                "attributes": {},
                                "childNodeCount": 1,
                                "children": [
                                    {
                                        "type": "node",
                                        "sharedId": any_string,
                                        "value": {
                                            "nodeType": 1,
                                            "localName": "span",
                                            "namespaceURI": "http://www.w3.org/1999/xhtml",
                                            "childNodeCount": 0,
                                            "attributes": {},
                                            "shadowRoot": None,
                                        },
                                    }
                                ],
                                "localName": "p",
                                "namespaceURI": "http://www.w3.org/1999/xhtml",
                                "nodeType": 1,
                                "shadowRoot": None,
                            },
                        },
                        {
                            "sharedId": any_string,
                            "type": "node",
                            "value": {
                                "attributes": {},
                                "childNodeCount": 0,
                                "localName": "br",
                                "namespaceURI": "http://www.w3.org/1999/xhtml",
                                "nodeType": 1,
                                "shadowRoot": None,
                            },
                        },
                    ],
                    "localName": "div",
                    "namespaceURI": "http://www.w3.org/1999/xhtml",
                    "nodeType": 1,
                    "shadowRoot": None,
                },
            },
        ),
    ],
)
async def test_max_dom_depth(
    bidi_session, top_context, get_test_page, max_dom_depth, expected
):
    await bidi_session.browsing_context.navigate(
        context=top_context["context"], url=get_test_page(), wait="complete"
    )
    result = await bidi_session.script.evaluate(
        expression="""document.querySelector("div#with-children")""",
        target=ContextTarget(top_context["context"]),
        await_promise=True,
        serialization_options=SerializationOptions(max_dom_depth=max_dom_depth),
    )

    recursive_compare(expected, result)


async def test_max_dom_depth_null(
    bidi_session,
    send_blocking_command,
    top_context,
    get_test_page,
):
    await bidi_session.browsing_context.navigate(
        context=top_context["context"], url=get_test_page(), wait="complete"
    )
    result = await send_blocking_command(
        "script.evaluate",
        {
            "expression": """document.querySelector("div#with-children")""",
            "target": ContextTarget(top_context["context"]),
            "awaitPromise": True,
            "serializationOptions": {"maxDomDepth": None},
        },
    )

    recursive_compare(
        {
            "type": "node",
            "sharedId": any_string,
            "value": {
                "nodeType": 1,
                "localName": "div",
                "namespaceURI": "http://www.w3.org/1999/xhtml",
                "childNodeCount": 2,
                "children": [
                    {
                        "type": "node",
                        "sharedId": any_string,
                        "value": {
                            "nodeType": 1,
                            "localName": "p",
                            "namespaceURI": "http://www.w3.org/1999/xhtml",
                            "childNodeCount": 1,
                            "children": [
                                {
                                    "type": "node",
                                    "sharedId": any_string,
                                    "value": {
                                        "nodeType": 1,
                                        "localName": "span",
                                        "namespaceURI": "http://www.w3.org/1999/xhtml",
                                        "childNodeCount": 0,
                                        "children": [],
                                        "attributes": {},
                                        "shadowRoot": None,
                                    },
                                }
                            ],
                            "attributes": {},
                            "shadowRoot": None,
                        },
                    },
                    {
                        "type": "node",
                        "sharedId": any_string,
                        "value": {
                            "nodeType": 1,
                            "localName": "br",
                            "namespaceURI": "http://www.w3.org/1999/xhtml",
                            "childNodeCount": 0,
                            "children": [],
                            "attributes": {},
                            "shadowRoot": None,
                        },
                    },
                ],
                "attributes": {"id": "with-children"},
                "shadowRoot": None,
            },
        },
        result["result"],
    )


@pytest.mark.parametrize(
    "max_object_depth, expected",
    [
        (
            None,
            {
                "type": "array",
                "value": [
                    {"type": "number", "value": 1},
                    {"type": "array", "value": [{"type": "number", "value": 2}]},
                ],
            },
        ),
        (0, {"type": "array"}),
        (
            1,
            {
                "type": "array",
                "value": [
                    {"type": "number", "value": 1},
                    {"type": "array"},
                ],
            },
        ),
        (
            2,
            {
                "type": "array",
                "value": [
                    {"type": "number", "value": 1},
                    {"type": "array", "value": [{"type": "number", "value": 2}]},
                ],
            },
        ),
    ],
)
async def test_max_object_depth(bidi_session, top_context, max_object_depth, expected):
    result = await bidi_session.script.evaluate(
        expression="[1, [2]]",
        target=ContextTarget(top_context["context"]),
        await_promise=True,
        serialization_options=SerializationOptions(max_object_depth=max_object_depth),
    )

    assert result == expected
