"""
Custom resolution that focuses on producing the most valid paths for all platforms while having the same
behaviour for similar errors.
"""
import ntpath
import sys
from pathlib import Path
from typing import Union

from clarabot_nano.utility.path.error import NtOSErrorCodes

if sys.platform.startswith("win"):

    def resolve_path(path: Union[Path, str], strict: bool = False) -> Path:
        """
        This resolution will always return with "\\?\" prefixed NT path. Which is desired as our path validation
        requires the extended prefix.
        Builtin resolving alternatives are insufficient:
            - The Path.resolve() does not preserve the proper path prefixes.
            - The os.path.realpath() does not have a strict mode to enforce successful resolution.

        Symlink type violation will raise PermissionError (WinError 5) normally, but some resolvers like
        os.path.realpath() for example will fall back to manually reading the link and following it. It's
        unclear if we want to do such a thing.
        """
        try:
            if strict:
                return Path(ntpath._getfinalpathname(path))
            # TODO: Not strict will just stop for symlink loop and return a partial result. This is inconsistent
            #  with POSIX where the resolve would raise.
            return Path(ntpath._getfinalpathname_nonstrict(path))
        except WindowsError as e:
            if e.winerror == NtOSErrorCodes.ERROR_CANT_RESOLVE_FILENAME:
                raise FileNotFoundError from e
            raise e


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

    def resolve_path(path: Union[Path, str], strict: bool = False) -> Path:
        """
        Coerce special symlink loop exception to an OSError.
        """
        if isinstance(path, str):
            path = Path(path)
        try:
            return path.resolve(strict)
        except RuntimeError as e:
            if e.args and isinstance(e.args[0], str) and e.args[0].startswith("Symlink loop "):
                raise FileNotFoundError from e
            raise


else:
    raise NotImplementedError()
