#!/usr/bin/env python
"""
模糊文件名匹配工具
用于匹配数据库记录名称和实际文件名之间的差异
"""

import os
import re
from difflib import SequenceMatcher

class FuzzyFilenameMatcher:
    """
    模糊文件名匹配器
    用于解决数据库记录名称与实际文件名不一致的问题
    """
    
    # 特殊字符映射表
    CHAR_MAPPINGS = {
        'ø': 'Ø',
        'é': 'e',
        'É': 'E',
        'ö': 'o',
        'ü': 'u',
        'ñ': 'n',
        'á': 'a',
        'ó': 'o',
        'ä': 'a',
        'ç': 'c',
        'í': 'i',
        'ú': 'u',
        'ê': 'e',
        'â': 'a',
        'è': 'e',
        'ù': 'u',
        'û': 'u',
        'î': 'i',
        'ï': 'i',
        'ë': 'e',
        'Ö': 'O',
        'Ü': 'U',
        'Ñ': 'N',
        'Á': 'A',
        'Ó': 'O',
        'Ú': 'U',
        'Í': 'I',
        'Î': 'I',
        'Ô': 'O',
        'Â': 'A',
        'Ã': 'A',
        'Å': 'A',
        'Æ': 'AE',
        'Ç': 'C',
        'È': 'E',
        'Ì': 'I',
        'Ò': 'O',
        'Ù': 'U',
        'Ý': 'Y',
        'ã': 'a',
        'å': 'a',
        'æ': 'ae',
        'ð': 'd',
        'ß': 'ss',
        'þ': 'th',
        'ÿ': 'y',
        'Œ': 'OE',
        'œ': 'oe',
        'Ÿ': 'Y'
    }
    
    def __init__(self, threshold=0.8):
        """
        初始化匹配器
        
        Args:
            threshold (float): 匹配阈值，低于此值将抛出异常
        """
        self.threshold = threshold
    
    def normalize_name(self, name):
        """
        标准化名称
        
        Args:
            name (str): 原始名称
            
        Returns:
            str: 标准化后的名称
        """
        # 替换特殊字符
        for original, replacement in self.CHAR_MAPPINGS.items():
            name = name.replace(original, replacement)
        
        # 移除多余的空格并替换为下划线
        name = re.sub(r'\s+', '_', name.strip())
        
        return name
    
    def fuzzy_match(self, db_name, filenames):
        """
        模糊匹配数据库名称和文件名列表
        
        Args:
            db_name (str): 数据库中的名称
            filenames (list): 文件名列表
            
        Returns:
            tuple: (best_match, similarity_score)
            
        Raises:
            ValueError: 当最佳匹配的相似度低于阈值时
        """
        if not filenames:
            raise ValueError("文件名列表不能为空")
        
        normalized_db_name = self.normalize_name(db_name)
        best_match = None
        best_score = 0.0
        
        for filename in filenames:
            # 去掉文件扩展名
            name_without_ext = os.path.splitext(filename)[0]
            
            # 计算相似度
            similarity = SequenceMatcher(None, normalized_db_name.lower(), name_without_ext.lower()).ratio()
            
            if similarity > best_score:
                best_score = similarity
                best_match = filename
        
        # 如果最佳匹配分数低于阈值，抛出异常
        if best_score < self.threshold:
            raise ValueError(f"找不到与 '{db_name}' 匹配的文件，最佳匹配 '{best_match}' 的相似度为 {best_score:.2%}，低于阈值 {self.threshold:.2%}")
        
        return best_match, best_score
    
    def get_all_matches(self, db_name, filenames):
        """
        获取所有可能的匹配项及其分数
        
        Args:
            db_name (str): 数据库中的名称
            filenames (list): 文件名列表
            
        Returns:
            list: 包含(文件名, 相似度)元组的列表，按相似度降序排列
        """
        if not filenames:
            return []
        
        normalized_db_name = self.normalize_name(db_name)
        matches = []
        
        for filename in filenames:
            # 去掉文件扩展名
            name_without_ext = os.path.splitext(filename)[0]
            
            # 计算相似度
            similarity = SequenceMatcher(None, normalized_db_name.lower(), name_without_ext.lower()).ratio()
            matches.append((filename, similarity))
        
        # 按相似度降序排序
        matches.sort(key=lambda x: x[1], reverse=True)
        return matches


def demo():
    """
    演示如何使用模糊文件名匹配器
    """
    # 示例数据
    db_players = [
        "Gabriel Magalhaes",
        "Martin Ødegaard",
        "Ben White",
        "Bukayo Saka"
    ]
    
    file_names = [
        "Gabriel_Magalhães.jpg",
        "Martin_Ødegaard.jpg",
        "Ben_White.jpg",
        "Bukayo_Saka.jpg"
    ]
    
    matcher = FuzzyFilenameMatcher(threshold=0.8)
    
    print("数据库名称 -> 文件名匹配:")
    print("-" * 50)
    
    for player in db_players:
        try:
            match, score = matcher.fuzzy_match(player, file_names)
            print(f"{player:<25} -> {match:<25} (相似度: {score:.2%})")
        except ValueError as e:
            print(f"{player:<25} -> 错误: {e}")
    
    print("\n详细匹配信息:")
    print("-" * 50)
    
    for player in db_players:
        matches = matcher.get_all_matches(player, file_names)
        print(f"\n{player}:")
        for filename, score in matches[:3]:  # 显示前3个最佳匹配
            status = "✓" if score >= matcher.threshold else "✗"
            print(f"  {status} {filename:<25} ({score:.2%})")


if __name__ == "__main__":
    demo()