import sys
import os
from enum import Enum
import inspect
from pathlib import Path

__all__ = ["Auto_Mode","getProjectPath","get_temp_path"]

class Auto_Mode(Enum):
    disable = 0  # 禁用自动查找，仅按层级查找 会获取当前使用的py文件所在的位置
    normal = 1  # 普通模式：仅检测常规Python项目标记
    high = 2  # 高敏感模式：额外检测.venv/.idea等特殊标记
    highest = 3  # 最高敏感模式：合并normal和high的所有标记

# def get_temp_path(relative_path=""):
#     """
#     获取应用程序资源路径（兼容普通运行和PyInstaller打包环境）
#     总是基于调用者脚本的位置进行解析
#
#     参数:
#         relative_path (str): 相对于基础路径的子路径
#
#     返回:
#         str: 完整的资源路径
#     """
#     try:
#         # PyInstaller打包后，从临时目录_MEIPASS加载
#         if getattr(sys, 'frozen', False):
#             base_path = sys._MEIPASS
#         else:
#             # 获取调用者脚本的路径
#             frame = inspect.stack()[1]
#             caller_path = frame.filename
#             base_path = str(Path(caller_path).parent.absolute())
#
#         # 拼接完整路径并规范化路径分隔符
#         full_path = os.path.normpath(os.path.join(base_path, relative_path))
#         return full_path
#     except Exception as e:
#         raise RuntimeError(f"Failed to determine resource path: {e}") from e
def get_temp_path(relative_path=""):
    """
    获取应用程序资源路径（兼容普通运行和PyInstaller/Nuitka打包环境）
    总是基于可执行文件的位置进行解析
    参数:
        relative_path (str): 相对于基础路径的子路径
    返回:
        str: 完整的资源路径
    """
    try:
        # 打包后，优先使用可执行文件所在目录
        if getattr(sys, 'frozen', False):
            base_path = os.path.dirname(sys.executable)
        else:
            # 获取调用者脚本的路径
            frame = inspect.stack()[1]
            caller_path = frame.filename
            base_path = str(Path(caller_path).parent.absolute())
        # 拼接完整路径并规范化路径分隔符
        full_path = os.path.normpath(os.path.join(base_path, relative_path))
        return full_path
    except Exception as e:
        raise RuntimeError(f"Failed to determine resource path: {e}") from e

# def getProjectPath(layer: int = 0, auto: Auto_Mode = Auto_Mode.normal ) -> str:
#     """
#     获取调用此库的主工程路径，支持四种模式：
#     1. 禁用自动查找（auto=Auto_Mode.disable）
#     2. 普通自动查找（auto=Auto_Mode.normal）
#     3. 高敏感度查找（auto=Auto_Mode.high）
#     4. 最高敏感度查找（auto=Auto_Mode.highest，合并normal和high的标记）
#
#     参数:
#         layer: 在找到工程路径后，再向上查找的目录层数 (0=不向上查找)
#         auto: 自动查找模式（参见Auto_Mode枚举）
#     返回:
#         str: 项目路径
#     异常:
#         ValueError: 如果layer是负数
#         RuntimeError: 如果无法确定路径
#     """
#     if layer < 0:
#         raise ValueError("layer参数不能为负数")
#
#     # 处理打包成exe的情况（忽略所有参数）
#     if getattr(sys, 'frozen', False):
#         return os.path.dirname(sys.executable)
#
#     # 获取主模块路径
#     main_module = sys.modules.get('__main__')
#     if main_module is None or not hasattr(main_module, '__file__'):
#         raise RuntimeError("无法确定主模块路径")
#
#     # 获取主模块文件绝对路径
#     main_file = os.path.abspath(main_module.__file__)
#     current_path = os.path.dirname(main_file)
#
#     # 非自动模式：直接使用当前路径作为工程路径
#     if auto == Auto_Mode.disable:
#         project_path = current_path
#     else:
#         # 自动模式：定义项目标记检测逻辑
#         def is_project_dir(path: str) -> bool:
#             """检查给定路径是否是项目根目录"""
#             # 基础标记（normal模式）
#             normal_markers = [
#                 'pyproject.toml',
#                 'setup.py',
#                 'setup.cfg',
#                 'MANIFEST.in',
#                 '.git',
#                 '.hg',
#                 'LICENSE',
#                 'Pipfile',
#                 'poetry.lock',
#                 '.projectroot',
#                 'README.md',
#                 '.gitignore',
#                 'requirements.txt'
#             ]
#
#             # 高敏感标记（high模式）
#             high_markers = [
#                 '.idea',  # PyCharm项目
#                 '.vscode',  # VS Code项目
#                 '.venv',  # 虚拟环境目录
#                 'venv',
#                 'env'
#             ]
#
#             # 根据模式选择标记组合
#             if auto == Auto_Mode.normal or auto == 1:
#                 markers = normal_markers
#             elif auto == Auto_Mode.high or auto == 2:
#                 markers = high_markers
#             elif auto == Auto_Mode.highest or auto == 3:  # Auto_Mode.highest
#                 markers = normal_markers + high_markers
#             else:
#                 raise Exception("This Mode is Not Exist!")
#
#             # 检查标记存在性（特殊处理目录类标记）
#             for marker in markers:
#                 target = os.path.join(path, marker)
#                 if not os.path.exists(target):
#                     continue
#
#                 # 特殊验证（避免误判子目录中的.idea/.venv等）
#                 if marker.startswith('.') and marker not in ('.git', '.hg'):
#                     if marker in ('.idea', '.vscode'):
#                         if not os.path.isdir(target):
#                             continue
#                     # 确保是顶层目录（父目录不存在相同标记）
#                     parent_marker = os.path.join(os.path.dirname(path), marker)
#                     if os.path.exists(parent_marker):
#                         continue
#
#                 return True
#             return False
#
#         # 从当前路径向上查找项目根目录
#         project_path = current_path
#         while True:
#             if is_project_dir(project_path):
#                 break
#             parent = os.path.dirname(project_path)
#             if parent == project_path:  # 到达根目录
#                 break
#             project_path = parent
#
#     # 无论什么模式，都根据layer参数向上返回父目录
#     if layer > 0:
#         for _ in range(layer):
#             parent = os.path.dirname(project_path)
#             if parent == project_path:  # 已经到达根目录
#                 break
#             project_path = parent
#
#     return project_path
def getProjectPath(layer: int = 0, auto: Auto_Mode = Auto_Mode.normal) -> str:
    """
    获取项目根目录路径（兼容打包和开发环境）

    参数:
        layer: 找到根目录后，再向上回溯的层数（0=不回溯）
        auto: 自动检测模式（见 Auto_Mode）

    返回:
        str: 规范化后的绝对路径

    异常:
        ValueError: 如果 layer 为负数
        RuntimeError: 如果路径检测失败
    """
    if layer < 0:
        raise ValueError("Layer must be >= 0")
    # --- 处理打包环境 ---
    if getattr(sys, 'frozen', False):
        base_path = os.path.dirname(sys.executable)  # 总是返回exe所在目录
        if layer == 0:
            return os.path.normpath(base_path)

        # 处理层级回溯
        for _ in range(layer):
            parent = os.path.dirname(base_path)
            if parent == base_path:  # 到达根目录
                break
            base_path = parent
        return os.path.normpath(base_path)
    # --- 非打包环境 ---
    # 获取主模块路径
    main_module = sys.modules.get('__main__')
    if not hasattr(main_module, '__file__'):
        raise RuntimeError("Cannot determine main module path")
    current_path = os.path.dirname(os.path.abspath(main_module.__file__))
    # 禁用自动检测模式
    if auto == Auto_Mode.disable:
        project_path = current_path
    else:
        # 定义项目标记检测函数
        def is_project_root(path: str) -> bool:
            """检测给定路径是否是项目根目录"""
            # 模式对应的检测标记
            normal_markers = {
                'pyproject.toml', 'setup.py', 'requirements.txt',
                '.git', '.hg', 'LICENSE', 'README.md', '.gitignore'
            }
            high_markers = {
                '.idea', '.vscode', '.venv', 'venv', 'env'
            }
            # 根据模式选择标记
            markers = set()
            if auto in (Auto_Mode.normal, Auto_Mode.highest):
                markers.update(normal_markers)
            if auto in (Auto_Mode.high, Auto_Mode.highest):
                markers.update(high_markers)
            # 检查标记存在性
            for marker in markers:
                target = os.path.join(path, marker)
                if not os.path.exists(target):
                    continue
                # 特殊验证（避免误判子目录中的.idea/.venv等）
                if marker.startswith('.'):
                    parent_marker = os.path.join(os.path.dirname(path), marker)
                    if os.path.exists(parent_marker):
                        continue  # 父目录存在相同标记，说明不是根目录

                return True
            return False

        # 向上查找项目根目录
        project_path = current_path
        while True:
            if is_project_root(project_path):
                break
            parent = os.path.dirname(project_path)
            if parent == project_path:  # 到达文件系统根目录
                project_path = current_path  # 回退到原始路径
                break
            project_path = parent
    # 处理层级回溯
    if layer > 0:
        for _ in range(layer):
            parent = os.path.dirname(project_path)
            if parent == project_path:  # 到达根目录
                break
            project_path = parent
    return os.path.normpath(project_path)

def is_executable() -> bool:
    return not sys.executable.endswith('python.exe')

def is_dir_exists(path: str) -> bool:
    return os.path.isdir(path)

def is_file_exists(path: str) -> bool:
    return os.path.isfile(path)
