"""
Test the header name handling
=============================

**Module:** ``tests.test_varname``

The tests in this module aim at testing the validation and cleaning of header/column names of CSV files. Those names
serve as arguments to test methods, and must therefore be valid and not shadow builtin names. Reserved names are checked
also.
"""

import sys
from typing import Optional

import pytest

from _ptcsvp.varname import is_valid_name, make_name_valid
from pytest_csv_params.exception import CsvHeaderNameInvalid


@pytest.mark.parametrize(
    ["var_name", "is_valid"],
    [
        ("var_name", True),
        ("varname", True),
        ("_varname", True),
        ("_varName", True),
        ("VarName", True),
        ("VarName_", True),
        ("Var1Name_", True),
        ("Var1Name_0", True),
        ("0_var_name", False),
        ("var name", False),
        ("Var Name", False),
        ("Var-Name", False),
        ("Var.Name", False),
        ("Var:Name", False),
        (":VarName", False),
        (".VarName", False),
        (";VarName", False),
        ("VarName+", False),
        ("VarName#", False),
        ("VarNäme", False),
        ("VarNÖme", False),
        ("Varßn_ame", False),
        ("def", False),
        ("next", False),
        ("if", False),
    ],
)
def test_is_valid_name(var_name: str, is_valid: bool) -> None:
    """
    This test case checks that the method :meth:`_ptcsvp.varname.is_valid_name` gives the right results. The test method
    is parametrized.

    :param var_name: The name to check
    :param is_valid: Expectation if this is a valid name
    """

    assert is_valid_name(var_name) == is_valid


@pytest.mark.parametrize(
    ["var_name", "valid_var_name", "raises_error"],
    [
        ("var_name", "var_name", False),
        ("4var_name", "_var_name", False),
        ("44_var_name", "_4_var_name", False),
        ("varName", "varName", False),
        ("var Name", "var_Name", False),
        (" varName", "_varName", False),
        (":varName", "_varName", False),
        ("var-name", "var_name", False),
        ("a" * 1025, None, True),
        ("abcd" * 300, None, True),
        ("continue", None, True),
        ("float", None, True),
        ("str", None, True),
    ],
)
def test_make_name_valid(var_name: str, valid_var_name: Optional[str], raises_error: bool) -> None:
    """
    This test case checks the method :meth:`_ptcsvp.varname.make_name_valid` builds valid names or throws matching
    exceptions if not possible. Therefore, it is parametrized.

    :param var_name: The variable name to try to make valid
    :param valid_var_name: The name as expected after made valid
    :param raises_error: Expect an error?
    """

    if raises_error:
        with pytest.raises(CsvHeaderNameInvalid) as raised_error:
            make_name_valid(var_name)
        assert raised_error.value.args[0] == f"'{var_name}' is not a valid variable name"
    else:
        should_be_valid = make_name_valid(var_name)
        assert should_be_valid == valid_var_name
        assert is_valid_name(should_be_valid)


@pytest.mark.skipif(sys.version_info < (3, 10), reason="Only relevant for python 3.10 and above")
@pytest.mark.parametrize(
    ["name"],
    [
        ("match",),
        ("_",),
    ],
)
def test_310_names(name: str) -> None:
    """
    There are a few names that are not valid when using python 3.10 and above. This parametrized test checks if they are
    marked as invalid by the method :meth:`_ptcsvp.varname.is_valid_name`.

    This test will be skipped on python versions below 3.10.

    :param name: An invalid name since python 3.10.
    """

    assert not is_valid_name(name)
