import difflib
import unicodedata
from typing import Dict, List


def normalize_text(text: str) -> str:
    """Loại bỏ dấu tiếng Việt, chuyển chữ thường, bỏ ký tự đặc biệt."""
    if not text:
        return ""
    text = str(text).lower()
    # Remove accents
    text = unicodedata.normalize('NFD', text).encode('ascii', 'ignore').decode('utf-8')
    # Keep only alphanumeric and space
    text = "".join(c for c in text if c.isalnum() or c.isspace())
    return " ".join(text.split())

def calculate_similarity(query: str, document: str) -> float:
    """Tính điểm tương đồng kết hợp Keyword Overlap (70%) và Fuzzy Match (30%)."""
    norm_q = normalize_text(query)
    norm_d = normalize_text(document)
    
    if not norm_q or not norm_d:
        return 0.0

    # 1. Fuzzy Match (bù trừ sai chính tả dính liền, gõ tắt)
    fuzzy_ratio = difflib.SequenceMatcher(None, norm_q, norm_d).ratio()

    # 2. Word Overlap
    q_words = set(norm_q.split())
    d_words = set(norm_d.split())
    
    if not q_words:
        return 0.0
        
    intersection = q_words.intersection(d_words)
    overlap_score = len(intersection) / len(q_words)  # % từ của query xuất hiện trong document
    
    # Tính điểm
    final_score = (overlap_score * 0.7) + (fuzzy_ratio * 0.3)
    return round(final_score * 100, 2)

def find_best_matches(query: str, faq_list: List[Dict], top_k: int = 3) -> List[Dict]:
    """Tìm Top K FAQ khớp nhất. faq_list = [{"id": ..., "question": ..., "answer": ...}, ...]"""
    results = []
    for faq in faq_list:
        q_text = faq.get("question", "")
        if not q_text:
            continue
            
        score = calculate_similarity(query, q_text)
        
        # Nếu điểm > 0, đưa vào ds
        if score > 5.0:  # Ngưỡng thấp để lọc
            results.append({
                "id": faq.get("id"),
                "question": q_text,
                "answer": faq.get("answer", ""),
                "category": faq.get("category", ""),
                "is_variant": faq.get("is_variant", 0),
                "score": score
            })
            
    # Sort giảm dần theo điểm
    results.sort(key=lambda x: x["score"], reverse=True)
    return results[:top_k]
