import random

import pytest

from konabot.plugins.trpg_roll.core import RollError, roll_expression


class FakeRandom:
    def __init__(self, randint_values: list[int] | None = None, choice_values: list[int] | None = None):
        self._randint_values = list(randint_values or [])
        self._choice_values = list(choice_values or [])

    def randint(self, _a: int, _b: int) -> int:
        assert self._randint_values
        return self._randint_values.pop(0)

    def choice(self, _seq):
        assert self._choice_values
        return self._choice_values.pop(0)


def test_roll_expression_basic():
    rng = FakeRandom(randint_values=[2, 4, 5])
    result = roll_expression("3d6", rng=rng)

    assert result.total == 11
    assert result.format() == "3d6 = 11\n+3d6=[2, 4, 5]"


def test_roll_expression_multiple_terms():
    rng = FakeRandom(randint_values=[14, 3, 1])
    result = roll_expression("d20+1d4-2", rng=rng)

    assert result.total == 15
    assert result.format() == "d20+1d4-2 = 15\n+1d20=[14] +1d4=[3] -2=2"


def test_roll_expression_df():
    rng = FakeRandom(choice_values=[-1, 0, 1, 1])
    result = roll_expression("4dF", rng=rng)

    assert result.total == 1
    assert result.format() == "4dF = 1\n+4dF=[-1, +0, +1, +1]"


@pytest.mark.parametrize(
    ("expr", "message"),
    [
        ("", "请提供要掷的表达式"),
        ("abc", "无法解析表达式"),
        ("1d0", "骰子面数必须大于 0"),
        ("0d6", "骰子个数必须大于 0"),
        ("101d6", "单项最多只能掷 100 个骰子"),
        ("1d1001", "骰子面数不能超过 1000"),
        ("201d1", "单项最多只能掷 100 个骰子"),
        ("1d6*2", "表达式中含有无法识别的内容"),
    ],
)
def test_roll_expression_invalid(expr: str, message: str):
    with pytest.raises(RollError, match=message):
        roll_expression(expr, rng=random.Random(0))


def test_roll_expression_total_roll_limit():
    with pytest.raises(RollError, match="一次最多只能实际掷 200 个骰子"):
        roll_expression("100d6+100d6+1d6", rng=random.Random(0))
