from unittest.mock import Mock

import pytest

from promium.assertions import BaseSoftAssertion, RequestSoftAssertion
from promium.base import Element


FALSE_PARAMS = [False, 0, "", [], {}, ()]
TRUE_PARAMS = [True, 1, "sada", [1], {"k": "test"}, (1, 2)]
EQUALS_PARAMS = [
    (1, 1),
    (0, 0),
    ("t", "t"),
    ("u", "u"),
    (False, False),
    (True, 1),
    (False, 0),
]
EQUALS_PARAMS_EXTENDED = [
    *EQUALS_PARAMS,
    ([1, "s", []], [1, "s", []]),
    ({"k": 1}, {"k": 1}),
]
NOT_EQUALS_PARAMS = [
    (1, 0),
    (0, "www"),
    ("t", "test"),
    ("u", "unicode"),
    (False, True),
    ([1, "s", []], [1, "s", ["test"]]),
    ({"k": []}, {"k": 1}),
]
CONTAIN_PARAMS = [
    (1, [1]),
    (2, {1, 2}),
    (12, (6, 12)),
    (156, list(range(120, 1000))),
    ("str", ["str"]),
    ("str", ["str"]),
    ("str", {"str"}),
    ("str", ("str",)),
    ("str", {"str": 1, "key": 2}),
    ("string", "test string"),
    ("string", "test string"),
    ("str", "teststr"),
]
NOT_CONTAIN_PARAMS = [
    (1, [0]),
    (2, {1, 6}),
    (12, (6, 1)),
    (156, list(range(120))),
    ("str1", ["str"]),
    ("string", ["str1"]),
    ("str", {"str1"}),
    ("str", ("tuple",)),
    ("str", {"str_key": 1, "key": 2}),
    ("string", "test "),
    ("string", "test"),
]
LESS_PARAMS = [(0, 1), ("sss", "ssss"), (False, True)]
GREATER_PARAMS = [(1, 0), ("sss", "s"), (True, False)]
NOT_LESS_EQUALS_PARAMS = [
    *GREATER_PARAMS,
    ("test", "t"),
    ("unicode", "u"),
    (True, False),
]
NOT_GREATER_EQUALS_PARAMS = [
    *LESS_PARAMS,
    (0, 1),
    ("t", "test"),
    ("u", "unicode"),
    (False, True),
]
INSTANCE_PARAMS = [
    ("", str),
    (1, int),
    ([], list),
    ({"k": False}, dict),
    ((1, 2), tuple),
    ([1], list),
    (True, bool),
    ("1", str),
    ("666", (int, str)),
]
NOT_INSTANCE_PARAMS = [
    (1, str),
    ("1", int),
    (1, bool),
    (0, bool),
    ({"k": 1}, str),
    ({"k": 1}, int),
    ([], (set, tuple)),
]
SPACES_PARAMS = [
    ("s ", "s"),
    ("\n\t \r", ""),
    ("\v|\f |\n", "| |"),
    (" |    |   ", "| |"),
]


class MockElement:
    def __init__(self, some_dict):
        self.some_dict = some_dict

    def get_attribute(self, name):
        return self.some_dict.get(name)


@pytest.mark.unit
@pytest.mark.parametrize("expr", TRUE_PARAMS)
def test_soft_assert_true_valid_data(expr):
    soft = BaseSoftAssertion()
    soft.soft_assert_true(expr)
    assert not soft.assertion_errors


@pytest.mark.unit
@pytest.mark.parametrize("expr", FALSE_PARAMS)
def test_soft_assert_true_not_valid_data(expr):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_true(expr)
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
@pytest.mark.parametrize("expr", FALSE_PARAMS)
def test_soft_assert_false_valid_data(expr):
    soft = BaseSoftAssertion()
    soft.soft_assert_false(expr)
    assert not soft.assertion_errors


@pytest.mark.unit
@pytest.mark.parametrize("expr", TRUE_PARAMS)
def test_soft_assert_false_not_valid_data(expr):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_false(expr)
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), EQUALS_PARAMS_EXTENDED)
def test_soft_assert_equals_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.soft_assert_equals(cur, exp)
    assert not soft.assertion_errors


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), NOT_EQUALS_PARAMS)
def test_soft_assert_equals_not_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_equals(cur, exp)
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), NOT_EQUALS_PARAMS)
def test_soft_assert_not_equals_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.soft_assert_not_equals(cur, exp)
    assert not soft.assertion_errors


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), EQUALS_PARAMS_EXTENDED)
def test_soft_assert_not_equals_not_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_not_equals(cur, exp)
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), CONTAIN_PARAMS)
def test_soft_assert_in_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.soft_assert_in(cur, exp)
    assert not soft.assertion_errors


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), NOT_CONTAIN_PARAMS)
def test_soft_assert_in_not_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_in(cur, exp)
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), NOT_CONTAIN_PARAMS)
def test_soft_assert_not_in_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.soft_assert_not_in(cur, exp)
    assert not soft.assertion_errors


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), CONTAIN_PARAMS)
def test_soft_assert_not_in_not_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_not_in(cur, exp)
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), LESS_PARAMS + EQUALS_PARAMS)
def test_soft_assert_less_equal_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.soft_assert_less_equal(cur, exp)
    assert not soft.assertion_errors


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), NOT_LESS_EQUALS_PARAMS)
def test_soft_assert_less_equal_not_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_less_equal(cur, exp)
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), LESS_PARAMS)
def test_soft_assert_less_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.soft_assert_less(cur, exp)
    assert not soft.assertion_errors


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), GREATER_PARAMS)
def test_soft_assert_less_not_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_less(cur, exp)
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), GREATER_PARAMS + EQUALS_PARAMS)
def test_soft_assert_greater_equal_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.soft_assert_greater_equal(cur, exp)
    assert not soft.assertion_errors


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), NOT_GREATER_EQUALS_PARAMS)
def test_soft_assert_greater_equal_not_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_greater_equal(cur, exp)
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), GREATER_PARAMS)
def test_soft_assert_greater_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.soft_assert_greater(cur, exp)
    assert not soft.assertion_errors


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), LESS_PARAMS)
def test_soft_assert_greater_not_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_greater(cur, exp)
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
def test_soft_assert_regexp_matches_valid_data():
    soft = BaseSoftAssertion()
    soft.soft_assert_regexp_matches("test text #43", r"\w{2}")
    assert not soft.assertion_errors


@pytest.mark.unit
def test_soft_assert_regexp_matches_not_valid_data():
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_regexp_matches("test text #43", r"\w{3:5}")
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
def test_soft_assert_disable_valid_data():
    element = Mock(Element, **{"get_attribute.return_value": True})
    soft = BaseSoftAssertion()
    soft.soft_assert_disable(element)
    assert not soft.assertion_errors


@pytest.mark.unit
def test_soft_assert_disable_not_valid_data():
    element = Mock(Element, **{"get_attribute.return_value": False})
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_disable(element)
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
def test_soft_assert_is_none_valid_data():
    soft = BaseSoftAssertion()
    soft.soft_assert_is_none(None)
    assert not soft.assertion_errors


@pytest.mark.unit
@pytest.mark.parametrize("param", ["none", 0, False, 1, "", [], {}])
def test_soft_assert_is_none_not_valid_data(param):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_is_none(param)
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
@pytest.mark.parametrize("param", ["none", 0, False, 1, "", [], {}])
def test_soft_assert_is_not_none_valid_data(param):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_is_not_none(param)
    assert not soft.assertion_errors


@pytest.mark.unit
def test_soft_assert_is_not_none_not_valid_data():
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_is_not_none(None)
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), INSTANCE_PARAMS)
def test_soft_assert_is_instance_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_is_instance(cur, exp)
    assert not soft.assertion_errors


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), NOT_INSTANCE_PARAMS)
def test_soft_assert_is_instance_not_valid_data(cur, exp):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_is_instance(cur, exp)
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
@pytest.mark.parametrize(("cur", "exp"), SPACES_PARAMS)
def test_soft_assert_equals_text_with_ignore_spaces_and_register(cur, exp):
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_equals_text_with_ignore_spaces_and_register(cur, exp)
    assert not soft.assertion_errors


@pytest.mark.unit
def test_soft_assert_schemas_valid_data():
    soft = BaseSoftAssertion()
    soft.soft_assert_schemas(
        current={"key": 1, "key2": [1, 2, 3], "key3": "3"},
        expected={"key": int, "key2": [int], "key3": str},
    )
    assert not soft.assertion_errors


@pytest.mark.unit
def test_soft_assert_schemas_not_valid_data():
    soft = BaseSoftAssertion()
    soft.soft_assert_schemas(
        current={"key": 1, "key2": [1, None, 3], "key3": None},
        expected={"key": str, "key2": [int], "key3": dict},
    )
    assert soft.assertion_errors
    assert len(soft.assertion_errors) == 1


@pytest.mark.unit
def test_assert_keys_and_instances_valid_data():
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.assert_keys_and_instances(
        actual_dict={"key": "1", "key2": [1, 2, 3], "key3": 3},
        expected_dict={"key": str, "key2": list, "key3": int},
    )
    assert not soft.assertion_errors


@pytest.mark.unit
def test_assert_keys_and_instances_not_valid_data():
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.assert_keys_and_instances(
        actual_dict={"key": 1, "key_2": [1, None, 3], "key_3": None},
        expected_dict={"key": int, "key_2": list, "key_3": str},
    )
    assert soft.assertion_errors


@pytest.mark.unit
def test_soft_assert_dicts_with_ignore_types():
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_dicts_with_ignore_types(
        current={"key": "1"},
        expected={"key": 1, "key2": 2, "key3": 3},
    )
    assert not soft.assertion_errors


@pytest.mark.unit
def test_soft_assert_dicts_with_ignore_types_not_valid_data():
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_dicts_with_ignore_types(
        current={"key": 2},
        expected={"key": 1, "key_2": 2, "key_3": 3},
    )
    assert soft.assertion_errors


@pytest.mark.unit
def test_soft_assert_equal_dict_from_clerk_magic():
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_equal_dict_from_clerk_magic(
        current_dict={"key1": "1", "key2": 2},
        expected_dict={"key2": 2, "key1": "1"},
    )
    assert not soft.assertion_errors


@pytest.mark.unit
def test_soft_assert_equal_dict_from_clerk_magic_not_valid_data():
    soft = BaseSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_equal_dict_from_clerk_magic(
        current_dict={"key_1": "1", "key_2": 2},
        expected_dict={"key_2": None, "key_3": "AAa"},
    )
    assert soft.assertion_errors


@pytest.mark.unit
def test_request_soft_assert_true():
    soft = RequestSoftAssertion()
    soft.assertion_errors = []
    soft.soft_assert_true(True)
    assert not soft.assertion_errors
