import base64
import itertools
import os
import sys

import pytest

from clarabot_nano_common.utility.path.sensitive import normalize_validate_sensitive_absolute_path, SensitiveValidationError
from clarabot_nano_common.utility.path.validate import ValidationError


def _test_sets(valid, invalid):
    for v_n in valid:
        try:
            normalize_validate_sensitive_absolute_path(v_n)
        except SensitiveValidationError as e:
            raise AssertionError(f"{v_n}") from e
    for i_n in invalid:
        with pytest.raises(SensitiveValidationError):
            normalize_validate_sensitive_absolute_path(i_n)


def _gen_sub(folder, prefixes=("",), sep=os.path.sep, self=True):
    names = [
        "a",
        "A",
        "Ő",
        base64.urlsafe_b64encode(os.urandom(3)).decode(),
        f"{base64.urlsafe_b64encode(os.urandom(3)).decode()}{sep}{base64.urlsafe_b64encode(os.urandom(3)).decode()}",
    ]
    lst = [f"{folder}{sep}{p}{n}" for p in prefixes for n in names]
    lst.extend([f"{p}{sep}" for p in lst])
    if self:
        lst.append(folder)
        lst.append(folder + sep)
    return lst


def test_normalize_validate_sensitive_absolute_path_universal():
    try:
        normalize_validate_sensitive_absolute_path("bin")
    except SensitiveValidationError:
        assert False
    except ValidationError:
        pass


@pytest.mark.skipif(not sys.platform.startswith("darwin"), reason="for darwin only")
def test_normalize_validate_sensitive_absolute_path_darwin():
    sys_roots = "bin|boot|dev|etc|lib|lib17|lib64|proc|root|run|sbin|sys|usr|var".split("|")
    sys_roots.extend([f"private/{sr}" for sr in sys_roots])
    sys_roots.extend("home|Applications|Developer|Library|System|cores".split("|"))
    sys_roots.extend(".vol|.file".split("|"))
    _test_sets(
        [
            *_gen_sub("/asd", prefixes=("", ".")),
            *_gen_sub("/tmp", prefixes=("", "."), self=False),
            *_gen_sub("/private/tmp", prefixes=("", "."), self=False),
            *_gen_sub("/Users/xy", prefixes=("",), self=False),
        ],
        [
            "/",
            *list(itertools.chain(*[_gen_sub(f"/{r}") for r in sys_roots])),
            *["/tmp", "/tmp/", "/private/tmp", "/private/tmp/"],
            *["/Users", "/Users/"],
            *_gen_sub("/Users/xy", prefixes=(".",)),
            *_gen_sub("/Users/xy/Library", prefixes=("", ".")),
        ],
    )


@pytest.mark.skipif(not sys.platform.startswith("linux"), reason="for linux/posix only")
def test_normalize_validate_sensitive_absolute_path_linux_posix():
    sys_roots = "bin|boot|dev|etc|lib|lib17|lib64|proc|root|run|sbin|sys|usr|var".split("|")
    _test_sets(
        [
            *_gen_sub("/asd", prefixes=("", ".")),
            *_gen_sub("/tmp", prefixes=("", "."), self=False),
            *_gen_sub("/home/xy", prefixes=("",), self=False),
        ],
        [
            "/",
            *list(itertools.chain(*[_gen_sub(f"/{r}") for r in sys_roots])),
            *["/tmp", "/tmp/"],
            *["/home", "/home/"],
            *_gen_sub("/home/xy", prefixes=(".",)),
        ],
    )


@pytest.mark.skipif(not sys.platform.startswith("win"), reason="for windows only")
def test_normalize_validate_sensitive_absolute_path_nt():
    sys_roots = "windows|WindOWs|Program Files|Program Files (x86)|ProgramData".split("|")
    _test_sets(
        [
            *_gen_sub("C:/asd", prefixes=("", ".")),
            *list(
                itertools.chain(*[_gen_sub(r, prefixes=("",), self=False) for r in ["C:/users/xy", "c:\\Users/Public"]])
            ),
        ],
        [
            *["c:/", "C:/", "C:\\"],
            *list(itertools.chain(*[_gen_sub(f"c:\\{r}") for r in sys_roots])),
            *list(itertools.chain(*[_gen_sub(f"c:/{r}", sep="/") for r in sys_roots])),
            *list(itertools.chain(*[_gen_sub(f"c:\\{r}", sep="/") for r in sys_roots])),
            *["c:/Users", "c:\\uSers", "C:/users/xy/.ssh", "c:\\Users/xy\\", "c:\\Users/Public", "c:\\Users/Public/"],
            *list(itertools.chain(*[_gen_sub(r, prefixes=(".",)) for r in ["C:/users/xy", "c:\\Users/Public"]])),
            *list(itertools.chain(*[_gen_sub(r) for r in ["C:/users/xy/AppData", "c:\\Users/Public/APPDATA"]])),
            *list(itertools.chain(*[_gen_sub(f"C:/Users/egér/AppData/{r}") for r in ["Roaming", "Local", "LocalLow"]])),
        ],
    )
