import pytest

from rich import errors
from rich.color import Color, ColorSystem, ColorType
from rich.style import Style, StyleStack


def test_str():
    assert str(Style(bold=False)) == "not bold"
    assert str(Style(color="red", bold=False)) == "not bold red"
    assert str(Style(color="red", bold=False, italic=True)) == "not bold italic red"
    assert str(Style()) == "none"
    assert str(Style(bold=True)) == "bold"
    assert str(Style(color="red", bold=True)) == "bold red"
    assert str(Style(color="red", bgcolor="black", bold=True)) == "bold red on black"
    all_styles = Style(
        color="red",
        bgcolor="black",
        bold=True,
        dim=True,
        italic=True,
        underline=True,
        blink=True,
        blink2=True,
        reverse=True,
        conceal=True,
        strike=True,
        underline2=True,
        frame=True,
        encircle=True,
        overline=True,
    )
    expected = "bold dim italic underline blink blink2 reverse conceal strike underline2 frame encircle overline red on black"
    assert str(all_styles) == expected
    assert str(Style(link="foo")) == "link foo"


def test_ansi_codes():
    all_styles = Style(
        color="red",
        bgcolor="black",
        bold=True,
        dim=True,
        italic=True,
        underline=True,
        blink=True,
        blink2=True,
        reverse=True,
        conceal=True,
        strike=True,
        underline2=True,
        frame=True,
        encircle=True,
        overline=True,
    )
    expected = "1;2;3;4;5;6;7;8;9;21;51;52;53;31;40"
    assert all_styles._make_ansi_codes(ColorSystem.TRUECOLOR) == expected


def test_repr():
    assert (
        repr(Style(bold=True, color="red"))
        == "Style(color=Color('red', ColorType.STANDARD, number=1), bold=True)"
    )


def test_eq():
    assert Style(bold=True, color="red") == Style(bold=True, color="red")
    assert Style(bold=True, color="red") != Style(bold=True, color="green")
    assert Style().__eq__("foo") == NotImplemented


def test_hash():
    assert isinstance(hash(Style()), int)


def test_empty():
    assert Style.null() == Style()


def test_bool():
    assert bool(Style()) is False
    assert bool(Style(bold=True)) is True
    assert bool(Style(color="red")) is True
    assert bool(Style.parse("")) is False


def test_color_property():
    assert Style(color="red").color == Color("red", ColorType.STANDARD, 1, None)


def test_bgcolor_property():
    assert Style(bgcolor="black").bgcolor == Color("black", ColorType.STANDARD, 0, None)


def test_parse():
    assert Style.parse("") == Style()
    assert Style.parse("red") == Style(color="red")
    assert Style.parse("not bold") == Style(bold=False)
    assert Style.parse("bold red on black") == Style(
        color="red", bgcolor="black", bold=True
    )
    assert Style.parse("bold link https://example.org") == Style(
        bold=True, link="https://example.org"
    )
    with pytest.raises(errors.StyleSyntaxError):
        Style.parse("on")
    with pytest.raises(errors.StyleSyntaxError):
        Style.parse("on nothing")
    with pytest.raises(errors.StyleSyntaxError):
        Style.parse("rgb(999,999,999)")
    with pytest.raises(errors.StyleSyntaxError):
        Style.parse("not monkey")
    with pytest.raises(errors.StyleSyntaxError):
        Style.parse("link")


def test_link_id():
    assert Style().link_id == ""
    assert Style.parse("").link_id == ""
    assert Style.parse("red").link_id == ""
    style = Style.parse("red link https://example.org")
    assert isinstance(style.link_id, str)
    assert len(style.link_id) > 1


def test_get_html_style():
    expected = "color: #7f7fbf; text-decoration-color: #7f7fbf; background-color: #800000; font-weight: bold; font-style: italic; text-decoration: underline; text-decoration: line-through; text-decoration: overline"
    html_style = Style(
        reverse=True,
        dim=True,
        color="red",
        bgcolor="blue",
        bold=True,
        italic=True,
        underline=True,
        strike=True,
        overline=True,
    ).get_html_style()
    print(repr(html_style))
    assert html_style == expected


def test_chain():
    assert Style.chain(Style(color="red"), Style(bold=True)) == Style(
        color="red", bold=True
    )


def test_copy():
    style = Style(color="red", bgcolor="black", italic=True)
    assert style == style.copy()
    assert style is not style.copy()


def test_render():
    assert Style(color="red").render("foo", color_system=None) == "foo"
    assert (
        Style(color="red", bgcolor="black", bold=True).render("foo")
        == "\x1b[1;31;40mfoo\x1b[0m"
    )
    assert Style().render("foo") == "foo"


def test_test():
    Style(color="red").test("hello")


def test_add():
    assert Style(color="red") + None == Style(color="red")


def test_iadd():
    style = Style(color="red")
    style += Style(bold=True)
    assert style == Style(color="red", bold=True)
    style += None
    assert style == Style(color="red", bold=True)


def test_style_stack():
    stack = StyleStack(Style(color="red"))
    repr(stack)
    assert stack.current == Style(color="red")
    stack.push(Style(bold=True))
    assert stack.current == Style(color="red", bold=True)
    stack.pop()
    assert stack.current == Style(color="red")


def test_pick_first():
    with pytest.raises(ValueError):
        Style.pick_first()


def test_background_style():
    assert Style(bold=True, color="yellow", bgcolor="red").background_style == Style(
        bgcolor="red"
    )


def test_without_color():
    style = Style(bold=True, color="red", bgcolor="blue")
    colorless_style = style.without_color
    assert colorless_style.color == None
    assert colorless_style.bgcolor == None
    assert colorless_style.bold == True
    null_style = Style.null()
    assert null_style.without_color == null_style


def test_meta():
    style = Style(bold=True, meta={"foo": "bar"})
    assert style.meta["foo"] == "bar"

    style += Style(meta={"egg": "baz"})

    assert style.meta == {"foo": "bar", "egg": "baz"}

    assert repr(style) == "Style(bold=True, meta={'foo': 'bar', 'egg': 'baz'})"


def test_from_meta():
    style = Style.from_meta({"foo": "bar"})
    assert style.color is None
    assert style.bold is None


def test_on():
    style = Style.on({"foo": "bar"}, click="CLICK") + Style(color="red")
    assert style.meta == {"foo": "bar", "@click": "CLICK"}


def test_clear_meta_and_links():
    style = Style.parse("bold red on black link https://example.org") + Style.on(
        click="CLICK"
    )

    assert style.meta == {"@click": "CLICK"}
    assert style.link == "https://example.org"
    assert style.color == Color.parse("red")
    assert style.bgcolor == Color.parse("black")
    assert style.bold
    assert not style.italic

    clear_style = style.clear_meta_and_links()

    assert clear_style.meta == {}
    assert clear_style.link == None
    assert clear_style.color == Color.parse("red")
    assert clear_style.bgcolor == Color.parse("black")
    assert clear_style.bold
    assert not clear_style.italic


def test_clear_meta_and_links_clears_hash():
    """Regression test for https://github.com/Textualize/rich/issues/2942."""

    style = Style.parse("bold red on black link https://example.org") + Style.on(
        click="CLICK"
    )
    hash(style)  # Force hash caching.

    assert style._hash is not None

    clear_style = style.clear_meta_and_links()
    assert clear_style._hash is None
