# -*- coding: utf-8 -*-
"""
@Project : VientianeArena
@File    : path_checker
@Author  : YL_top01
@Date    : 2025/8/25 16:06
"""





# Built-in modules
import os
import re
from pathlib import Path


# Third-party modules
# (无第三方依赖)

# Local modules
from yltop.recording.checks.common import CheckLevel
from yltop.recording.checks.checkexecutor_base import CheckExecutor
from yltop.recording.core.logger import record_error
from yltop.recording.errors.path import PathFormatError, PathNotExistsError
from src.yltop.recording.utils.path import get_resource_path


class PathCheckExecutor(CheckExecutor):
    """路径检查执行器"""

    def __init__(self, level: CheckLevel = CheckLevel.LOG, debug: bool = False):
        super().__init__(level)
        self.debug = debug
        # 在初始化时创建验证器映射
        self.PATH_VALIDATORS = {
            "windows": self._validate_windows_path,
            "posix": self._validate_posix_path
        }

    def check_format(self, path: str, context: dict = None) -> bool:
        """检查路径格式"""
        condition = self._is_valid_path_format(path)
        error = PathFormatError(path)
        return self.execute(condition, error, context)

    def check_exists(self, path: str, context: dict = None) -> bool:
        """检查路径存在"""
        condition = Path(path).exists()
        error = PathNotExistsError(path)
        return self.execute(condition, error, context)

    def full_check(self, path: str, context: dict = None) -> bool:
        """完整路径检查（格式+存在）"""
        if not self.check_format(path, context):
            return False
        return self.check_exists(path, context)

    def _log(self, message: str):
        """记录调试信息"""
        if self.debug:
            print(f"[PathCheck] {message}")

    def _is_valid_path_format(self, path: str) -> bool:
        """验证路径格式的主要方法"""
        try:
            self._log(f"开始验证路径: {path}")

            # 空路径检查
            if not path.strip():
                self._log("路径为空")
                return False

            # 检查空字节（所有系统）
            if '\0' in path:
                self._log("路径包含空字节")
                return False

            # 规范化路径
            normalized = os.path.normpath(path)
            self._log(f"规范化路径: {normalized}")

            # 获取当前系统类型
            system = "windows" if os.name == "nt" else "posix"
            self._log(f"检测到操作系统: {system}")

            # 获取对应的验证器
            validator = self.PATH_VALIDATORS.get(system)
            if not validator:
                self._log(f"不支持的操作系统: {os.name}")
                return False

            # 执行系统特定的验证
            return validator(normalized)

        except Exception as e:
            self._log(f"验证过程中出错: {str(e)}")
            return False

    def _validate_windows_path(self, normalized: str) -> bool:
        """Windows专用路径验证"""
        self._log("Windows系统路径检查")

        # 拆分驱动器号和剩余路径
        drive, tail = os.path.splitdrive(normalized)
        self._log(f"驱动器号: '{drive}', 剩余路径: '{tail}'")

        # 验证驱动器号格式
        if drive:
            if len(drive) != 2 or drive[1] != ':' or not drive[0].isalpha():
                self._log(f"无效驱动器号格式: '{drive}'")
                return False
            self._log("驱动器号格式有效")

        # 非法字符检查
        illegal_chars = '<>"|?*'
        found_illegal = [char for char in illegal_chars if char in tail]
        if found_illegal:
            self._log(f"发现非法字符: {found_illegal}")
            return False
        self._log("非法字符检查通过")

        # 控制字符检查
        control_chars = [char for char in tail if ord(char) < 32]
        if control_chars:
            self._log(f"路径包含控制字符: {control_chars}")
            return False
        self._log("控制字符检查通过")

        # 分割路径组件
        parts = [part for part in re.split(r'[\\/]+', tail) if part]  # 注意这里使用 tail
        self._log(f"路径组件: {parts}")

        # 检查每个部分是否有效
        for i, part in enumerate(parts):
            # 跳过特殊目录引用
            if part in ('.', '..'):
                self._log(f"跳过特殊目录: '{part}'")
                continue

            # 文件名长度检查
            if len(part) > 255:
                self._log(f"组件过长(>255): '{part}'")
                return False

            # 文件名不能以空格开头或结尾
            if part.startswith(' ') or part.endswith(' '):
                self._log(f"组件包含首尾空格: '{part}'")
                return False

            # Windows 保留名称检查
            filename = part.upper()

            # 检查保留名称
            if filename in ['CON', 'PRN', 'AUX', 'NUL']:
                self._log(f"保留名称: '{part}'")
                return False

            if filename.startswith(('COM', 'LPT')):
                suffix = filename[3:]
                if suffix.isdigit() and 1 <= int(suffix) <= 9:
                    self._log(f"保留名称: '{part}'")
                    return False

        self._log("所有Windows路径检查通过")
        return True

    def _validate_posix_path(self, normalized: str) -> bool:
        """POSIX专用路径验证"""
        self._log("POSIX系统路径检查")

        # 控制字符检查
        control_chars = [char for char in normalized if ord(char) < 32]
        if control_chars:
            self._log(f"路径包含控制字符: {control_chars}")
            return False
        self._log("控制字符检查通过")

        # 分割路径组件
        parts = [part for part in re.split(r'[\\/]+', normalized) if part]
        self._log(f"路径组件: {parts}")

        # 检查每个部分是否有效
        for part in parts:
            # 跳过特殊目录引用
            if part in ('.', '..'):
                self._log(f"跳过特殊目录: '{part}'")
                continue

            # 文件名长度检查
            if len(part) > 255:
                self._log(f"组件过长(>255): '{part}'")
                return False

            # 文件名不能以空格开头或结尾
            if part.startswith(' ') or part.endswith(' '):
                self._log(f"组件包含首尾空格: '{part}'")
                return False

            # POSIX 保留字符检查
            if part.startswith('-'):
                self._log(f"组件以连字符开头: '{part}'")
                return False

        self._log("所有POSIX路径检查通过")
        return True

    def check_resource_path(self, relative_path: str, context: dict = None) -> str:
        """
        检查资源路径（自动处理打包环境）

        返回:
            验证通过的绝对路径（验证失败时根据level处理）
        """
        try:
            path = get_resource_path(relative_path, validate=False)

            # 执行完整路径检查
            if self.full_check(path, context):
                return path

            return None
        except Exception as e:
            record_error(e)
            if self.level == CheckLevel.ASSERT:
                raise
            return None