import pytest

from colored.colored import (Colored, attr, back_rgb, bg, fg, fore_rgb, set_tty_aware,
                              style, stylize, stylize_interactive)
from colored.exceptions import InvalidColor, InvalidHexColor, InvalidStyle
from colored.library import Library

ESC: str = '\x1b['
FOREGROUND_RGB: str = f'{ESC}38;2;'
BACKGROUND_RGB: str = f'{ESC}48;2;'
END: str = 'm'


def test_style_func() -> None:
    assert style('bold') == f'{ESC}1{END}'


def test_style_func_with_underline_color() -> None:
    for code in Library.COLORS.values():
        result = style('underline', code)
        assert result != ''


def test_fore_rgb_func() -> None:
    assert fore_rgb(255, 0, 0) == f'{FOREGROUND_RGB}255;0;0{END}'


def test_back_rgb_func() -> None:
    assert back_rgb(0, 255, 0) == f'{BACKGROUND_RGB}0;255;0{END}'


def test_fore_rgb_percentages() -> None:
    result = fore_rgb('100%', '0%', '0%')
    assert FOREGROUND_RGB in result


def test_back_rgb_percentages() -> None:
    result = back_rgb('0%', '100%', '0%')
    assert BACKGROUND_RGB in result


def test_fore_rgb_clamping() -> None:
    assert fore_rgb(300, -1, 128) == f'{FOREGROUND_RGB}255;0;128{END}'


def test_attr_func() -> None:
    assert attr('bold') == f'{ESC}1{END}'


def test_fg_func() -> None:
    for name, code in Library.COLORS.items():
        assert fg(name) == f'{ESC}38;5;{code}{END}'


def test_bg_func() -> None:
    for name, code in Library.COLORS.items():
        assert bg(name) == f'{ESC}48;5;{code}{END}'


def test_stylize() -> None:
    result = stylize('Hello', fore_rgb(255, 0, 0))
    assert 'Hello' in result
    assert style('reset') in result


def test_stylize_no_reset() -> None:
    result = stylize('Hello', fore_rgb(255, 0, 0), reset=False)
    assert 'Hello' in result
    assert style('reset') not in result


def test_stylize_interactive() -> None:
    result = stylize_interactive('Hello', fore_rgb(255, 0, 0))
    assert 'Hello' in result
    assert '\x01' in result
    assert '\x02' in result


def test_hex_foreground() -> None:
    result = Colored('#ff0000').foreground()
    assert result != ''
    assert FOREGROUND_RGB not in result or ESC in result


def test_hex_background() -> None:
    result = Colored('#00ff00').background()
    assert result != ''


def test_set_tty_aware() -> None:
    set_tty_aware(False)
    assert Colored('red').foreground() != ''
    set_tty_aware(True)


def test_force_color_disabled(monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setenv('FORCE_COLOR', '0')
    assert Colored('red').foreground() == ''


def test_no_color_disables(monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.delenv('FORCE_COLOR', raising=False)
    monkeypatch.setenv('NO_COLOR', '1')
    assert Colored('red').foreground() == ''


def test_invalid_color_raises() -> None:
    with pytest.raises(InvalidColor):
        Colored('not_a_color').foreground()


def test_invalid_hex_color_raises() -> None:
    with pytest.raises(InvalidHexColor):
        Colored('#gggggg').foreground()


def test_invalid_style_raises() -> None:
    with pytest.raises(InvalidStyle):
        Colored('not_a_style').attribute()
