import sys

import pytest

from clarabot_nano.utility.path.validate import validate_name, ValidationError

# create path names for validation
PATH_NAMES_INVALID_ALL_ = [".", "..", "/", "//", "C:/", "/bin", "bin/", "asd\x00"]
PATH_NAMES_INVALID_NT_ = ["\\", "\\\\", "C:", "C:\\", "asd ", "asd.", "asd . "]
PATH_NAMES_INVALID_NT_EXCEPT_PATH_ = ["asd\\x", "asd\\"]  # exceptions for path-inclusion validation
PATH_NAMES_INVALID_NT_DOS_ = []
PATH_NAMES_VALID_ALL_ = ["asd", "XT", ".yes.qt", "ŐőáűŰÍí", "$Volume", "NUL x.a"]
PATH_NAMES_VALID_POSIX_ = ["...", "$%!+:\\?*<#&|@>\"~'", ". ", " . ", ".. ", " .. ", "\\ ", " \\ ", "asd ", "asd."]


def _generate_path_name_variants(c):
    tmp = [f"asd{c}x", f"{c}xyz", f"asd{c}"]
    return tmp + [t + " " for t in tmp]


def _generate_nt_reserved_name_variants_invalid(n):
    tmp = [f"{n} ", f"{n}.", f"{n}.xy ", f"{n}:", f"{n} :", f"{n} :a", f"{n} : a . b"]
    tmp.extend([t.lower() for t in tmp])
    return tmp


def _generate_nt_reserved_name_variants(n):
    tmp = [n, f"{n}.xy", f"{n} . xy", f"{n}  . x . y"]
    tmp.extend([t.lower() for t in tmp])
    return tmp


for c_ in "\x00/":  # invalid for all
    PATH_NAMES_INVALID_ALL_.extend(_generate_path_name_variants(c_))
for c_ in ':*?|\\<>"':  # invalid for nt
    PATH_NAMES_INVALID_NT_.extend(_generate_path_name_variants(c_))
for i_ in range(1, 32):  # invalid for nt
    PATH_NAMES_INVALID_NT_.extend(_generate_path_name_variants(chr(i_)))
for n_ in ["CON", "CONIN$", "CONOUT$", "PRN", "AUX", "NUL"]:
    PATH_NAMES_INVALID_NT_.extend(_generate_nt_reserved_name_variants_invalid(n_))
    PATH_NAMES_INVALID_NT_DOS_.extend(_generate_nt_reserved_name_variants(n_))
for c_ in "123456789\xb9\xb2\xb3":
    PATH_NAMES_INVALID_NT_.extend(_generate_nt_reserved_name_variants_invalid(f"COM{c_}"))
    PATH_NAMES_INVALID_NT_.extend(_generate_nt_reserved_name_variants_invalid(f"LPT{c_}"))
    PATH_NAMES_INVALID_NT_DOS_.extend(_generate_nt_reserved_name_variants(f"COM{c_}"))
    PATH_NAMES_INVALID_NT_DOS_.extend(_generate_nt_reserved_name_variants(f"LPT{c_}"))


def _validate_name_sets(valid, invalid, **kwargs):
    for v_n in valid:
        try:
            validate_name(v_n, **kwargs)
        except ValidationError as e:
            raise AssertionError(f"{v_n}") from e
    for i_n in invalid:
        with pytest.raises(ValidationError):
            validate_name(i_n, **kwargs)


def test_utility_path_validate_name_universal():
    validate_name("a" * 255)
    with pytest.raises(ValidationError):
        validate_name("a" * 256)
    validate_name("a")
    with pytest.raises(ValidationError):
        validate_name("")
    _validate_name_sets(PATH_NAMES_VALID_ALL_, PATH_NAMES_INVALID_ALL_)


@pytest.mark.skipif(sys.platform.startswith("win"), reason="for posix only")
def test_utility_path_validate_name_posix():
    _validate_name_sets(PATH_NAMES_VALID_POSIX_ + PATH_NAMES_INVALID_NT_ + PATH_NAMES_INVALID_NT_DOS_, [])


@pytest.mark.skipif(not sys.platform.startswith("win"), reason="for windows only")
def test_utility_path_validate_name_nt():
    _validate_name_sets([], PATH_NAMES_VALID_POSIX_ + PATH_NAMES_INVALID_NT_ + PATH_NAMES_INVALID_NT_DOS_)
    _validate_name_sets(PATH_NAMES_INVALID_NT_DOS_, PATH_NAMES_VALID_POSIX_ + PATH_NAMES_INVALID_NT_, file=False)
    _validate_name_sets(PATH_NAMES_INVALID_NT_DOS_, PATH_NAMES_VALID_POSIX_ + PATH_NAMES_INVALID_NT_, dos=False)
