import socket
import sys

import pytest

from clarabot_nano.utility.path.validate import ValidationError, normalize_absolute_path, validate_path

_LOCALHOST_NAME = socket.gethostname()

# "abnormal" items can't be normalized as absolute paths because they are relative-like paths
# "invalid" items seem to be absolute paths, but validating them will fail
# "absolute" items can be normalized and validated
PATH_ABNORMAL_ALL_ = [
    "C:",
    "C:asd",
    "asd",
    r"\\.\C:",
    r"\\.\UnC\localHost\c$",
    r"//./UnC\127.0.0.1/C$",
    r"//./UnC\::1/C$",
    r"\temp\test-file.txt",
    r"\\?\c:temp\test-file.txt",
    r"c:temp\test-file.txt",
]
PATH_INVALID_ALL_ = []
PATH_ABSOLUTE_NT_ = [  # ABNORMAL for POSIX
    "c:",
    "C:",
    r"\\?\c:",
    r"\\?\C:",
    # the above paths that end with ":" are only normalizable if something beginning with a slash is added to them
    "//LOCALHOST/c$",
    f"//{_LOCALHOST_NAME}/c$",
    r"\\localHost\C$",
    r"\\127.0.0.1\C$",
    r"\\::1\C$",
    rf"\\{_LOCALHOST_NAME}\C$",
    r"\\?\UNC\localHost\C$",
    r"\\?\UnC\localHost\c$",
    rf"\\?\UnC\{_LOCALHOST_NAME}\c$",
    r"\\?\UnC\127.0.0.1\C$",
    r"//?/UnC\127.0.0.1/C$",
    rf"//?/UNC\{_LOCALHOST_NAME}/C$",
    r"//?/UnC\::1/C$",
]
PATH_INVALID_NT_ = [  # ABNORMAL for POSIX
    "//LOCALHOST/c$/ /a",
    "//LOCALHOST/c$/./a",
    "//LOCALHOST/c$/../a",
    "//LOCALHOST/c$/. ./a",
    "//LOCALHOST/c$/.. /a",
]
PATH_ABSOLUTE_POSIX_ = [  # ABNORMAL for NT
    "/",
    r"/\asd",
    "/asd",
    r"/asd\\.x.txt",
    "/asd/.x.txt",
]
PATH_INVALID_POSIX_ = [  # ABNORMAL for NT
    "/t/./a",
    "/t/../a",
    "/t//a",
]


def _normalize_validate_return(p) -> str:
    np = normalize_absolute_path(p)
    validate_path(np)
    return np


def test_utility_path_validate_normalize_absolute_path_universal():
    for p in PATH_ABNORMAL_ALL_:
        with pytest.raises(ValidationError):
            normalize_absolute_path(p)
    for p in PATH_INVALID_ALL_:
        np = normalize_absolute_path(p)
        with pytest.raises(ValidationError):
            validate_path(np)


@pytest.mark.skipif(sys.platform.startswith("win"), reason="for posix only")
def test_utility_path_validate_normalize_absolute_path_posix():
    for p in PATH_ABSOLUTE_NT_ + PATH_INVALID_NT_:
        with pytest.raises(ValidationError):
            normalize_absolute_path(p)
    for p in PATH_INVALID_POSIX_:
        np = normalize_absolute_path(p)
        with pytest.raises(ValidationError):
            validate_path(np)
    for p in PATH_ABSOLUTE_POSIX_:
        assert _normalize_validate_return(p) == p
        if p != "/":
            assert _normalize_validate_return(f"{p}/") == p


@pytest.mark.skipif(not sys.platform.startswith("win"), reason="for windows only")
def test_utility_path_validate_normalize_absolute_path_nt():
    for p in PATH_ABSOLUTE_POSIX_ + PATH_INVALID_POSIX_:
        with pytest.raises(ValidationError):
            normalize_absolute_path(p)
    for p in PATH_INVALID_NT_:
        np = normalize_absolute_path(p)
        with pytest.raises(ValidationError):
            validate_path(np)
    for prefix in PATH_ABSOLUTE_NT_:
        for p in [r"\asd", "/asd", r"\asd\.x.txt", "/asd/.x.txt"]:
            assert _normalize_validate_return(f"{prefix}{p}") == f"//?/C:{p}"
        if prefix.endswith(":"):
            with pytest.raises(ValidationError, match="Path is not absolute or has invalid prefix"):
                normalize_absolute_path(prefix)
        else:
            assert _normalize_validate_return(prefix) == "//?/C:/"
        assert _normalize_validate_return(f"{prefix}/") == "//?/C:/"
        assert _normalize_validate_return(f"{prefix}\\/") == "//?/C:/"
