"""
Windows has such exotic features and implementation that we need a separate module for its utilities.
TODO: add some static tests for these codes
"""
import os
from typing import List, Tuple

import pythoncom
from win32com.storagecon import STGM_READ
from win32comext.shell import shell
from win32comext.shell import shellcon


def read_shortcut_target_path(lnk_paths: List[str]) -> List[str]:
    """
    Shortcut files (*.lnk) are used for special locations. These can refer to a great variety of things
    other than file-system objects. Target objects that cannot be associated with a path are ignored.

    Created by using a pywin32 test-code as a base and from the raw C example from MSDN:
    https://docs.microsoft.com/en-us/windows/win32/shell/links?redirectedfrom=MSDN#resolving-a-shortcut

    The resolution of shortcuts is actually only meaningful for broken target locations. They are supposed
    to automatically restore the link by filesystem operation logs and heuristics. This can be a time
    consuming operations and it is useless most of the time, so we opt not to ever resolve shortcuts.
    When they break, the system administrator will update them if they are to be fixed at all.
    """
    target_paths = []
    i_shell_link = pythoncom.CoCreateInstance(
        shell.CLSID_ShellLink, None, pythoncom.CLSCTX_INPROC_SERVER, shell.IID_IShellLink
    )
    i_persist_file = i_shell_link.QueryInterface(pythoncom.IID_IPersistFile)
    for lnk_path in lnk_paths:
        try:
            i_persist_file.Load(lnk_path, STGM_READ)
        except pythoncom.com_error:
            continue
        # NOTE: Resolution could be done here. (if it was needed)
        # i_shell_link.Resolve(None, shell.SLR_ANY_MATCH | shell.SLR_NO_UI)
        # Target-path retrieval.
        # https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ishelllinka-getpath
        # The flags for the path retrieval are a little confusing. According to MSDN:
        #   - SLGP_SHORTPATH        : Get as short (8.3) path.
        #   - SLGP_UNCPRIORITY      : Unsupported, do not use.
        #   - SLGP_RAWPATH          : Raw value with unresolved environment values.
        #   - SLGP_RELATIVEPRIORITY : Relative path to the current-directory. (Win Vista or later)
        # Of these the UNC would be interesting, but that should not be used for some reason. So we use no flag
        # and just  see what we get.
        target_path, target_data = i_shell_link.GetPath(0)
        if target_path:
            target_paths.append(target_path)
    return target_paths


def list_network_shortcut_paths() -> List[str]:
    """
    List the shortcut files of the saved network locations of the user.
    """
    shortcut_paths = []
    net_hood = shell.SHGetFolderPath(0, shellcon.CSIDL_NETHOOD, None, 0)
    if net_hood and os.path.isdir(net_hood):
        for network_name in os.listdir(net_hood):
            shortcut_path = os.path.join(net_hood, network_name, "target.lnk")
            if os.path.isfile(shortcut_path):
                shortcut_paths.append(shortcut_path)
    return shortcut_paths


def get_system_profiles_paths() -> Tuple[List[str], str]:
    """
    Unlike on POSIX, the Windows filesystem hierarchy has evolved more over the years in seemingly ad-hoc fashion.
    It even has numerous ways to customize the place of the Windows directory and user homes, so we need to
    dynamically collect these.
    Returns a list of system-sensitive paths and the path to the user's home (profile) root directory.
    The collected paths are assumed to be canonical. Ie. they are free of symlinks and are absolute.
    """
    system_paths = set()
    for folder_id in [
        shellcon.FOLDERID_ProgramData,  # C:\ProgramData
        shellcon.FOLDERID_ProgramFiles,  # C:\Program Files
        shellcon.FOLDERID_ProgramFilesX64,  # C:\Program Files
        shellcon.FOLDERID_ProgramFilesX86,  # C:\Program Files (x86)
        shellcon.FOLDERID_Windows,  # C:\Windows
    ]:
        try:
            system_paths.add(shell.SHGetKnownFolderPath(folder_id, 0, None))
        except pythoncom.com_error:
            continue
    profiles_path = shell.SHGetKnownFolderPath(shellcon.FOLDERID_UserProfiles, 0, None)  # C:\Users
    return list(system_paths), profiles_path
