"""
Collection of sensitive paths to avoid serving for drives.
The paths are resolved and normalized at startup. They never change.
"""
import re
import sys
from pathlib import Path
from typing import Union

from clarabot_nano.utility.path.common import normalize_validate_absolute_path
from clarabot_nano.utility.path.validate import ValidationError


class SensitiveValidationError(ValidationError):
    pass


if sys.platform.startswith("win"):
    from clarabot_nano.utility.path.nt import get_system_profiles_paths

    def _create_sensitive_regexp() -> re.Pattern:
        system_paths, profiles_path = get_system_profiles_paths()
        recursive_patterns = set()
        exact_patterns = set()

        def _normalised_path_as_re_pattern(p: Union[str, Path]) -> str:
            # NOTE: force consistent separators
            return re.escape(normalize_validate_absolute_path(p).replace("\\", "/"))

        def _collect_patterns(p: str, first_recursive: bool = True):
            p = Path(p)
            (recursive_patterns if first_recursive else exact_patterns).add(_normalised_path_as_re_pattern(p))
            while len(p.parts) > 1:
                p = p.parent
                exact_patterns.add(_normalised_path_as_re_pattern(p))

        # create recursive exclusions for system directories and exact exclusions for all their parents
        for system_path in system_paths:
            _collect_patterns(system_path)
        _collect_patterns(profiles_path, first_recursive=False)

        recursive_re = f"^(?:{'|'.join(recursive_patterns)})(?:/|$)"
        exact_re = f"^(?:{'|'.join(exact_patterns)})$"
        # NOTE: We're treating paths in the home starting with "." (dot) as sensitive, because unix software (through
        # cygwin or mingw for example) often put sensitive data here by the POSIX conventions.
        home_re = rf"^{_normalised_path_as_re_pattern(profiles_path)}/[^/]+(?:/(?:\..+|AppData|AppData/.+))?$"

        return re.compile(rf"{exact_re}|{recursive_re}|{home_re}", re.IGNORECASE | re.DOTALL)

    SENSITIVE_PATHS = _create_sensitive_regexp()

    def normalize_validate_sensitive_absolute_path(path: Union[str, Path]) -> str:
        path = normalize_validate_absolute_path(path).replace("\\", "/")  # NOTE: force consistent separators
        if SENSITIVE_PATHS.match(path):
            raise SensitiveValidationError("Path is sensitive")
        return path


elif sys.platform.startswith("linux") or sys.platform.startswith("darwin"):  # POSIX

    if sys.platform.startswith("darwin"):
        SENSITIVE_PATHS = re.compile(
            r"^/$"  # root exactly
            # generic posix dirs in the root and the /private paths recursively
            r"|^/(?:private/)?(?:bin|boot|dev|etc|lib\d*|proc|root|run|sbin|sys|usr|var)(?:/|$)"
            # linux home (not utilized on MacOS), MacOS system and hidden dirs in root recursively
            r"|^/(?:home|Applications|Developer|Library|System|cores|\.[^/]+)(?:/|$)"
            # user homes exactly, Library and hidden in homes recursively
            r"|^/Users(?:/[^/]+(?:/(?:\..+|Library(?:/.+)?))?)?$"
            r"|^/private$"  # this exactly
            r"|^(?:/private)?/tmp$",  # these exactly
            re.DOTALL,
        )
    else:  # Linux or generic POSIX
        SENSITIVE_PATHS = re.compile(
            r"^/$"  # root exactly
            r"|^/(?:bin|boot|dev|etc|lib\d*|proc|root|run|sbin|sys|usr|var)(?:/|$)"  # generic posix dirs recursively
            r"|^/(?:home(?:/[^/]+(?:/\..+)?)?|tmp)$",  # user homes and temp exactly, hidden in homes recursively
            re.DOTALL,
        )

    def normalize_validate_sensitive_absolute_path(path: Union[str, Path]) -> str:
        path = normalize_validate_absolute_path(path)
        if SENSITIVE_PATHS.match(path):
            raise SensitiveValidationError("Path is sensitive")
        return path


else:
    raise NotImplementedError()
