"""
功能 3: 色盲友好性检测
确保颜色方案对色盲人群可访问
"""
import warnings
from typing import List, Tuple, Dict


def hex_to_rgb(hex_color: str) -> Tuple[int, int, int]:
    """十六进制转 RGB"""
    hex_color = hex_color.lstrip('#')
    return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))


def rgb_to_hex(rgb: Tuple[int, int, int]) -> str:
    """RGB 转十六进制"""
    return '#{:02x}{:02x}{:02x}'.format(
        max(0, min(255, int(rgb[0]))),
        max(0, min(255, int(rgb[1]))),
        max(0, min(255, int(rgb[2])))
    )


def simulate_colorblind_vision(colors: List[str], cvd_type: str = "deuteranopia") -> List[str]:
    """
    模拟色盲视角
    使用简化的色盲模拟算法
    
    Args:
        colors: 颜色列表（hex 格式）
        cvd_type: 色盲类型
            - "protanopia": 红色盲（缺少 L 锥细胞）
            - "deuteranopia": 绿色盲（缺少 M 锥细胞）
            - "tritanopia": 蓝色盲（缺少 S 锥细胞）
    
    Returns:
        模拟后的颜色列表
        
    Note:
        这是基于 Brettel 等人（1997）算法的简化版本
        完整实现可以使用 daltonlens 或 colorspacious 库
    """
    # 色盲模拟矩阵（简化版）
    cvd_matrices = {
        "protanopia": [  # 红色盲
            [0.567, 0.433, 0.0],
            [0.558, 0.442, 0.0],
            [0.0, 0.242, 0.758]
        ],
        "deuteranopia": [  # 绿色盲（最常见）
            [0.625, 0.375, 0.0],
            [0.7, 0.3, 0.0],
            [0.0, 0.3, 0.7]
        ],
        "tritanopia": [  # 蓝色盲
            [0.95, 0.05, 0.0],
            [0.0, 0.433, 0.567],
            [0.0, 0.475, 0.525]
        ]
    }
    
    if cvd_type not in cvd_matrices:
        warnings.warn(f"Unknown CVD type: {cvd_type}, using deuteranopia", UserWarning)
        cvd_type = "deuteranopia"
    
    matrix = cvd_matrices[cvd_type]
    simulated = []
    
    for color in colors:
        rgb = hex_to_rgb(color)
        r, g, b = rgb
        
        # 应用变换矩阵
        new_r = matrix[0][0] * r + matrix[0][1] * g + matrix[0][2] * b
        new_g = matrix[1][0] * r + matrix[1][1] * g + matrix[1][2] * b
        new_b = matrix[2][0] * r + matrix[2][1] * g + matrix[2][2] * b
        
        # 钳制到 0-255
        new_rgb = (
            max(0, min(255, int(new_r))),
            max(0, min(255, int(new_g))),
            max(0, min(255, int(new_b)))
        )
        
        simulated.append(rgb_to_hex(new_rgb))
    
    return simulated


def calculate_color_contrast(color1: str, color2: str) -> float:
    """
    计算两个颜色的对比度（WCAG 2.0 标准）
    
    Args:
        color1, color2: 十六进制颜色
    
    Returns:
        对比度值 (1.0 - 21.0)
        
    WCAG Standards:
        - AA level (minimum): 4.5:1 for normal text, 3:1 for large text
        - AAA level (enhanced): 7:1 for normal text, 4.5:1 for large text
    """
    def relative_luminance(rgb):
        """计算相对亮度"""
        r, g, b = [x / 255.0 for x in rgb]
        
        # sRGB to linear RGB
        def to_linear(val):
            if val <= 0.03928:
                return val / 12.92
            return ((val + 0.055) / 1.055) ** 2.4
        
        r = to_linear(r)
        g = to_linear(g)
        b = to_linear(b)
        
        # Calculate luminance
        return 0.2126 * r + 0.7152 * g + 0.0722 * b
    
    rgb1 = hex_to_rgb(color1)
    rgb2 = hex_to_rgb(color2)
    
    l1 = relative_luminance(rgb1)
    l2 = relative_luminance(rgb2)
    
    # 对比度公式
    lighter = max(l1, l2)
    darker = min(l1, l2)
    contrast = (lighter + 0.05) / (darker + 0.05)
    
    return contrast


def calculate_perceptual_distance(color1: str, color2: str) -> float:
    """
    计算两个颜色的感知距离（简化版 Delta E）
    
    Args:
        color1, color2: 十六进制颜色
    
    Returns:
        感知距离（0-100+）
        
    Interpretation:
        - < 1.0: 几乎看不出差别
        - 1.0 - 2.0: 仔细看能看出差别
        - 2.0 - 10.0: 明显差别
        - > 10.0: 非常明显的差别
    """
    rgb1 = hex_to_rgb(color1)
    rgb2 = hex_to_rgb(color2)
    
    # 简化的 Delta E (Euclidean distance in RGB space)
    # 实际生产中应该在 LAB 空间计算
    dr = (rgb1[0] - rgb2[0]) / 255.0
    dg = (rgb1[1] - rgb2[1]) / 255.0
    db = (rgb1[2] - rgb2[2]) / 255.0
    
    # 加权欧氏距离（考虑人眼对绿色更敏感）
    distance = ((2 * dr * dr + 4 * dg * dg + 3 * db * db) ** 0.5) * 100
    
    return distance


def check_colorblind_safety(colors: List[str], 
                            min_contrast: float = 3.0,
                            min_distance: float = 10.0,
                            verbose: bool = True) -> Dict:
    """
    检查颜色方案的色盲友好性
    
    Args:
        colors: 颜色列表（hex 格式）
        min_contrast: 最小对比度要求（默认 3.0，符合 WCAG AA 大文本标准）
        min_distance: 最小感知距离要求
        verbose: 是否打印详细信息
    
    Returns:
        检查结果字典，包含：
        - safe: 是否对所有色盲类型友好
        - warnings: 警告信息列表
        - cvd_analysis: 各类色盲的详细分析
        - suggestions: 改进建议
    """
    results = {
        "safe": True,
        "warnings": [],
        "cvd_analysis": {},
        "suggestions": []
    }
    
    cvd_types = {
        "protanopia": "red-blind (1% of males)",
        "deuteranopia": "green-blind (1% of males, most common)",
        "tritanopia": "blue-blind (0.001% of population, rare)"
    }
    
    for cvd_type, description in cvd_types.items():
        # 模拟色盲视角
        simulated = simulate_colorblind_vision(colors, cvd_type)
        
        # 检查相邻颜色的对比度和距离
        min_observed_contrast = float('inf')
        min_observed_distance = float('inf')
        problem_pairs = []
        
        for i in range(len(simulated)):
            for j in range(i + 1, len(simulated)):
                contrast = calculate_color_contrast(simulated[i], simulated[j])
                distance = calculate_perceptual_distance(simulated[i], simulated[j])
                
                min_observed_contrast = min(min_observed_contrast, contrast)
                min_observed_distance = min(min_observed_distance, distance)
                
                if contrast < min_contrast or distance < min_distance:
                    problem_pairs.append({
                        'pair': (i, j),
                        'contrast': contrast,
                        'distance': distance
                    })
        
        # 记录分析结果
        results["cvd_analysis"][cvd_type] = {
            "description": description,
            "min_contrast": min_observed_contrast,
            "min_distance": min_observed_distance,
            "problem_pairs": problem_pairs,
            "safe": len(problem_pairs) == 0
        }
        
        if problem_pairs:
            results["safe"] = False
            results["warnings"].append(
                f"{cvd_type} ({description}): "
                f"{len(problem_pairs)} color pairs may be hard to distinguish"
            )
    
    # 生成改进建议
    if not results["safe"]:
        results["suggestions"].append(
            "Consider using a colorblind-safe palette like 'okabe-ito' or 'paul-tol-bright'"
        )
        results["suggestions"].append(
            "Add additional visual encodings (markers, line styles, textures)"
        )
        results["suggestions"].append(
            "Increase color contrast by adjusting lightness values"
        )
    
    # 打印详细信息
    if verbose:
        print("\n" + "=" * 70)
        print("Colorblind Safety Check Results")
        print("=" * 70)
        
        if results["safe"]:
            print("\n✓ Color scheme is colorblind-safe for all CVD types!")
        else:
            print("\n⚠ Color scheme may not be accessible to some users:")
            for warning in results["warnings"]:
                print(f"  - {warning}")
        
        print("\nDetailed Analysis:")
        for cvd_type, analysis in results["cvd_analysis"].items():
            status = "✓ PASS" if analysis["safe"] else "✗ FAIL"
            print(f"\n  {cvd_type} ({analysis['description']}): {status}")
            print(f"    Min contrast: {analysis['min_contrast']:.2f} (threshold: {min_contrast:.2f})")
            print(f"    Min distance: {analysis['min_distance']:.2f} (threshold: {min_distance:.2f})")
        
        if results["suggestions"]:
            print("\nSuggestions:")
            for suggestion in results["suggestions"]:
                print(f"  • {suggestion}")
        
        print("=" * 70)
    
    return results


if __name__ == "__main__":
    # 测试
    print("Accessibility Check Demo")
    
    # Test 1: NPG 调色板
    print("\n[Test 1] NPG palette:")
    npg_colors = ['#E64B35', '#4DBBD5', '#00A087', '#3C5488', '#F39B7F']
    check_colorblind_safety(npg_colors)
    
    # Test 2: Okabe-Ito 调色板（专门设计为色盲友好）
    print("\n[Test 2] Okabe-Ito palette:")
    okabe_colors = ['#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00', '#CC79A7']
    check_colorblind_safety(okabe_colors)





