from dataclasses import dataclass

from hrepr import H
from hrepr import hrepr as real_hrepr
from hrepr.h import styledir

from .common import one_test_per_assert

css_hrepr = open(f"{styledir}/hrepr.css", encoding="utf-8").read()
hrepr = real_hrepr.variant(fill_resources=False)


@dataclass
class Point:
    x: int
    y: int


class Opaque:
    pass


def hshort(x, **kw):
    return hrepr(x, max_depth=0, **kw)


@one_test_per_assert
def test_singletons():
    assert hrepr(True) == H.span["hreprv-True"]("True")
    assert hrepr(False) == H.span["hreprv-False"]("False")
    assert hrepr(None) == H.span["hreprv-None"]("None")


@one_test_per_assert
def test_numbers():
    assert hrepr(123) == H.span["hreprt-int"]("123")
    assert hrepr(1.25) == H.span["hreprt-float"]("1.25")


@one_test_per_assert
def test_string():
    assert hshort("hello") == H.span["hreprt-str"]("hello")
    assert hrepr("3   spaces") == H.span["hreprt-str"]("3   spaces")
    assert hrepr("hello this is a bit long") == H.span["hreprt-str"](
        "hello this is a bit long"
    )
    assert hshort("hello this is a bit long") == H.span["hreprt-str"](
        "hello this is a b..."
    )
    assert hshort("hello this is a bit long", string_cutoff=10) == H.span[
        "hreprt-str"
    ]("hello t...")
    assert hshort("hello this is a bit long", string_cutoff=5) == H.span[
        "hreprt-str"
    ]("he...")
    assert hshort("hello this is a bit long", string_cutoff=10000) == H.span[
        "hreprt-str"
    ]("hello this is a bit long")


@one_test_per_assert
def test_bytes():
    assert hrepr(b"hello") == H.span["hreprt-bytes"]("68656c6c6f")
    assert hshort(b"hello") == H.span["hreprt-bytes"]("68656c6c6f")
    assert hrepr(b"hello this is a bit long") == H.span["hreprt-bytes"](
        "68656c6c6f2074686973206973206120626974206c6f6e67"
    )
    assert hshort(b"hello this is a bit long") == H.span["hreprt-bytes"](
        "68656c6c6f2074686..."
    )


def test_function():
    assert hrepr(Opaque) == H.span["hreprk-class"](
        H.span["hrepr-defn-key"]("class"),
        " ",
        H.span["hrepr-defn-name"]("Opaque"),
    )


def test_structures():
    for typ, o, c in (
        (tuple, "(", ")"),
        (list, "[", "]"),
        (set, "{", "}"),
        (frozenset, "{", "}"),
    ):
        clsname = typ.__name__
        assert hrepr(typ((1, 2))) == H.div[
            f"hreprt-{clsname}", "hrepr-bracketed"
        ](
            H.div["hrepr-open"](o),
            H.div["hreprl-h", "hrepr-body"](
                H.div(H.span["hreprt-int"]("1")),
                H.div(H.span["hreprt-int"]("2")),
            ),
            H.div["hrepr-close"](c),
        )


def test_short_structures():
    for val, o, c in (
        ((1, 2), "(", ")"),
        ([1, 2], "[", "]"),
        ({1, 2}, "{", "}"),
        (frozenset({1, 2}), "{", "}"),
        ({"x": 1, "y": 2}, "{", "}"),
    ):
        clsname = type(val).__name__
        assert hrepr(val, max_depth=0) == H.div[
            f"hreprt-{clsname}", "hrepr-bracketed"
        ](
            H.div["hrepr-open"](o),
            H.div["hreprl-s", "hrepr-body"](H.div("...")),
            H.div["hrepr-close"](c),
        )


def test_dict():
    pt = {"x": 1, "y": 2}
    assert hrepr(pt) == H.div["hreprt-dict", "hrepr-bracketed"](
        H.div["hrepr-open"]("{"),
        H.table["hrepr-body"](
            H.tr(
                H.td(H.span["hreprt-str"]("x")),
                H.td["hrepr-delim"](": "),
                H.td(H.span["hreprt-int"]("1")),
            ),
            H.tr(
                H.td(H.span["hreprt-str"]("y")),
                H.td["hrepr-delim"](": "),
                H.td(H.span["hreprt-int"]("2")),
            ),
        ),
        H.div["hrepr-close"]("}"),
    )


def test_dataclass():
    pt = Point(1, 2)

    assert hrepr(pt) == H.div["hreprt-Point", "hrepr-instance", "hreprl-v"](
        H.div["hrepr-title"]("Point"),
        H.table["hrepr-body"](
            H.tr(
                H.td(H.span["hreprt-symbol"]("x")),
                H.td["hrepr-delim"]("="),
                H.td(H.span["hreprt-int"]("1")),
            ),
            H.tr(
                H.td(H.span["hreprt-symbol"]("y")),
                H.td["hrepr-delim"]("="),
                H.td(H.span["hreprt-int"]("2")),
            ),
        ),
    )

    assert hrepr(pt, max_depth=0) == H.div[
        "hreprt-Point", "hrepr-instance", "hreprl-s"
    ](
        H.div["hrepr-title"]("Point"),
        H.div["hreprl-s", "hrepr-body"](H.div("...")),
    )


def test_tag():
    tg = H.span["hello"](1, 2, H.b("there"))
    assert hrepr(tg) == tg


def test_multiref():
    li = [1, 2]
    lili = [li, li]

    assert hrepr(lili) == H.div["hreprt-list", "hrepr-bracketed"](
        H.div["hrepr-open"]("["),
        H.div["hreprl-h", "hrepr-body"](
            H.div(
                H.div["hrepr-refbox"](
                    H.span["hrepr-ref"]("#", 1, "="),
                    H.div["hreprt-list", "hrepr-bracketed"](
                        H.div["hrepr-open"]("["),
                        H.div["hreprl-h", "hrepr-body"](
                            H.div(H.span["hreprt-int"]("1")),
                            H.div(H.span["hreprt-int"]("2")),
                        ),
                        H.div["hrepr-close"]("]"),
                    ),
                )
            ),
            H.div(
                H.div["hrepr-refbox"](
                    H.span["hrepr-ref"]("#", 1, "="),
                    H.div["hreprt-list", "hrepr-bracketed"](
                        H.div["hrepr-open"]("["),
                        H.div["hreprl-s", "hrepr-body"](H.div("..."),),
                        H.div["hrepr-close"]("]"),
                    ),
                )
            ),
        ),
        H.div["hrepr-close"]("]"),
    )

    assert hrepr(lili, shortrefs=True) == H.div[
        "hreprt-list", "hrepr-bracketed"
    ](
        H.div["hrepr-open"]("["),
        H.div["hreprl-h", "hrepr-body"](
            H.div(
                H.div["hrepr-refbox"](
                    H.span["hrepr-ref"]("#", 1, "="),
                    H.div["hreprt-list", "hrepr-bracketed"](
                        H.div["hrepr-open"]("["),
                        H.div["hreprl-h", "hrepr-body"](
                            H.div(H.span["hreprt-int"]("1")),
                            H.div(H.span["hreprt-int"]("2")),
                        ),
                        H.div["hrepr-close"]("]"),
                    ),
                )
            ),
            H.div(H.span["hrepr-ref"]("#", 1)),
        ),
        H.div["hrepr-close"]("]"),
    )


def test_recursive():
    li = [1]
    li.append(li)

    assert hrepr(li) == H.div["hrepr-refbox"](
        H.span["hrepr-ref"]("#", 1, "="),
        H.div["hreprt-list", "hrepr-bracketed"](
            H.div["hrepr-open"]("["),
            H.div["hreprl-h", "hrepr-body"](
                H.div(H.span["hreprt-int"]("1")),
                H.div(
                    H.div["hrepr-refbox"](
                        H.span["hrepr-ref"]("⟳", 1, "="),
                        H.div["hreprt-list", "hrepr-bracketed"](
                            H.div["hrepr-open"]("["),
                            H.div["hreprl-s", "hrepr-body"](H.div("..."),),
                            H.div["hrepr-close"]("]"),
                        ),
                    )
                ),
            ),
            H.div["hrepr-close"]("]"),
        ),
    )

    assert hrepr(li, shortrefs=True) == H.div["hrepr-refbox"](
        H.span["hrepr-ref"]("#", 1, "="),
        H.div["hreprt-list", "hrepr-bracketed"](
            H.div["hrepr-open"]("["),
            H.div["hreprl-h", "hrepr-body"](
                H.div(H.span["hreprt-int"]("1")),
                H.div(H.span["hrepr-ref"]("⟳", 1)),
            ),
            H.div["hrepr-close"]("]"),
        ),
    )


def test_unsupported():
    assert hshort(Opaque()) == H.span["hreprt-Opaque"](
        "<", "tests.test_hrepr.Opaque", ">"
    )


def test_as_page():
    utf8 = H.meta(
        {"http-equiv": "Content-type"}, content="text/html", charset="UTF-8"
    )
    assert real_hrepr.page(1) == H.inline(
        H.raw("<!DOCTYPE html>"),
        H.html(H.head(utf8, H.style(css_hrepr)), H.body(real_hrepr(1)),),
    )


def test_hrepr_multiarg():
    assert hrepr(1, 2) == H.inline(
        H.span["hreprt-int"]("1"), H.span["hreprt-int"]("2"),
    )


def test_preprocess():
    assert hrepr(1, preprocess=lambda x, hrepr: x + 1) == H.span["hreprt-int"](
        "2"
    )


def test_postprocess():
    assert hrepr(1, postprocess=lambda x, obj, hrepr: x["newclass"]) == H.span[
        "newclass", "hreprt-int"
    ]("1")

[((10, 8, 10, 48), 'hrepr.hrepr.variant', 'real_hrepr.variant', (), '', True, 'from hrepr import hrepr as real_hrepr\n'), ((274, 11, 276, 5), 'hrepr.H.meta', 'H.meta', (), '', False, 'from hrepr import H\n'), ((167, 31, 167, 43), 'hrepr.H.b', 'H.b', ({(167, 35, 167, 42): '"""there"""'}, {}), "('there')", False, 'from hrepr import H\n'), ((277, 11, 277, 29), 'hrepr.hrepr.page', 'real_hrepr.page', ({(277, 27, 277, 28): '(1)'}, {}), '(1)', True, 'from hrepr import hrepr as real_hrepr\n'), ((278, 8, 278, 32), 'hrepr.H.raw', 'H.raw', ({(278, 14, 278, 31): '"""<!DOCTYPE html>"""'}, {}), "('<!DOCTYPE html>')", False, 'from hrepr import H\n'), ((162, 40, 162, 52), 'hrepr.H.div', 'H.div', ({(162, 46, 162, 51): '"""..."""'}, {}), "('...')", False, 'from hrepr import H\n'), ((114, 44, 114, 56), 'hrepr.H.div', 'H.div', ({(114, 50, 114, 55): '"""..."""'}, {}), "('...')", False, 'from hrepr import H\n'), ((279, 28, 279, 46), 'hrepr.H.style', 'H.style', ({(279, 36, 279, 45): 'css_hrepr'}, {}), '(css_hrepr)', False, 'from hrepr import H\n'), ((279, 56, 279, 69), 'hrepr.hrepr', 'real_hrepr', ({(279, 67, 279, 68): '(1)'}, {}), '(1)', True, 'from hrepr import hrepr as real_hrepr\n'), ((196, 56, 196, 68), 'hrepr.H.div', 'H.div', ({(196, 62, 196, 67): '"""..."""'}, {}), "('...')", False, 'from hrepr import H\n'), ((244, 60, 244, 72), 'hrepr.H.div', 'H.div', ({(244, 66, 244, 71): '"""..."""'}, {}), "('...')", False, 'from hrepr import H\n')]