import sys
from pathlib import Path, PurePath

import pytest
from clarabot_nano_common.utility.path.common import (
    ensure_path,
    get_path_flavour,
    posix_hierarchy_iter,
    normalize_validate_relative_path_to_root,
)
from clarabot_nano_common.utility.path.validate import ValidationError

from clarabot_nano_tests.testing.file import temp_path


def test_utility_path_common_get_path_flavour(tmpdir):
    assert PurePath(str(temp_path(tmpdir)))._flavour is get_path_flavour()


def test_utility_path_common_ensure_path(tmpdir):
    for v in [None, False, True, b"", "", 0, [], (), {}, set(), object, object()]:
        with pytest.raises(ValidationError):
            ensure_path(v)
    for v in [b"/tmp", 54, ["/tmp"], ("/tmp",), {"/tmp": "/tmp"}, {"/tmp"}]:
        with pytest.raises(ValidationError):
            ensure_path(v)
    for v in [str(temp_path(tmpdir))]:
        assert isinstance(ensure_path(v), Path)
        assert isinstance(ensure_path(ensure_path(v)), Path)


def test_utility_path_normalize_validate_relative_path_to_root():
    root = Path(r"\\?\c:\tmp") if sys.platform.startswith("win") else Path("/tmp")
    for p in (
        [
            Path(r"\\?\c:\tmp\x"),
            Path(r"\\?\c:\tmp\x"),
            Path(r"c:\tmp\x"),
            Path("c:/tmp/x"),
            Path("\\\\?\\c:\\"),
            Path("c:/"),
        ]
        if sys.platform.startswith("win")
        else [
            Path("/tmp/x"),
            Path("/"),
        ]
    ):
        with pytest.raises(ValidationError):
            normalize_validate_relative_path_to_root(p, root)
    for n in ["b" * 256, "..", "\x00"]:
        with pytest.raises(ValidationError):
            normalize_validate_relative_path_to_root(n, root)
        with pytest.raises(ValidationError):
            normalize_validate_relative_path_to_root(n + "/a", root)
        with pytest.raises(ValidationError):
            normalize_validate_relative_path_to_root("a/" + n, root)
        with pytest.raises(ValidationError):
            normalize_validate_relative_path_to_root("a/" + n + "/c", root)
    assert normalize_validate_relative_path_to_root("a/b", root) == root / "a/b"
    assert normalize_validate_relative_path_to_root("", root) == root
    assert normalize_validate_relative_path_to_root(".", root) == root


def test_utility_path_posix_hierarchy_iter():
    assert list(posix_hierarchy_iter("")) == []
    assert list(posix_hierarchy_iter("/")) == ["/"]
    assert list(posix_hierarchy_iter("/tmp")) == ["/", "/tmp"]
    assert list(posix_hierarchy_iter("/tmp/xy")) == ["/", "/tmp", "/tmp/xy"]
    assert list(posix_hierarchy_iter("/tmp/xy/a")) == ["/", "/tmp", "/tmp/xy", "/tmp/xy/a"]
    assert list(posix_hierarchy_iter("/tmp/xy/a/")) == ["/", "/tmp", "/tmp/xy", "/tmp/xy/a"]
    assert list(posix_hierarchy_iter("//localhost/c$/xy/b")) == [
        "//",  # is this something useful?
        "//localhost",
        "//localhost/c$",
        "//localhost/c$/xy",
        "//localhost/c$/xy/b",
    ]
    assert list(posix_hierarchy_iter("c:/")) == ["c:"]
    assert list(posix_hierarchy_iter("c:/xy")) == ["c:", "c:/xy"]
    assert list(posix_hierarchy_iter("c:/xy/")) == ["c:", "c:/xy"]
    assert list(posix_hierarchy_iter("tmp")) == ["tmp"]
    assert list(posix_hierarchy_iter("tmp/xy")) == ["tmp", "tmp/xy"]
    assert list(posix_hierarchy_iter("tmp/xy/ab")) == ["tmp", "tmp/xy", "tmp/xy/ab"]
