from cvs_manager.models import LanguageProficiency
import spacy
from spacy.matcher import PhraseMatcher
import re
from enum import Enum
from typing import List, Dict




# Load spaCy model
_nlp = spacy.load("en_core_web_sm")

# Known languages list (extend as needed)
LANGUAGES = [
    "English", "French", "Spanish", "German", "Chinese", "Arabic", "Russian",
    "Portuguese", "Japanese", "Hindi", "Italian", "Dutch"
]

# Proficiency variants mapping to your enum
PROFICIENCY_MAP = {
    # Native
    "native": LanguageProficiency.NATIVE,
    "bilingual": LanguageProficiency.NATIVE,
    "near native": LanguageProficiency.NATIVE,
    # Fluent
    "fluent": LanguageProficiency.FLUENT,
    "full professional proficiency": LanguageProficiency.FLUENT,
    "professional": LanguageProficiency.FLUENT,
    "professional working proficiency": LanguageProficiency.FLUENT,
    "conversational": LanguageProficiency.FLUENT,
    # Intermediate
    "intermediate": LanguageProficiency.INTERMEDIATE,
    "limited working proficiency": LanguageProficiency.INTERMEDIATE,
    "working proficiency": LanguageProficiency.INTERMEDIATE,
    # Basic
    "basic": LanguageProficiency.BASIC,
    "elementary": LanguageProficiency.BASIC,
    "beginner": LanguageProficiency.BASIC,
    "novice": LanguageProficiency.BASIC,
}

# PhraseMatcher for languages
matcher = PhraseMatcher(_nlp.vocab, attr="LOWER")
patterns = [_nlp.make_doc(lang) for lang in LANGUAGES]
matcher.add("LANGUAGE", patterns)

# Regex to find proficiency words
PROF_PATTERN = re.compile(
    r"\b(" + "|".join(re.escape(key) for key in PROFICIENCY_MAP.keys()) + r")\b",
    re.I
)


def normalize_proficiency(prof_text: str) -> LanguageProficiency:
    if not prof_text:
        return LanguageProficiency.BASIC
    prof_lower = prof_text.lower()
    # Find closest match
    for key, val in PROFICIENCY_MAP.items():
        if key in prof_lower:
            return val
    return LanguageProficiency.BASIC


def extract_languages(text: str) -> List[Dict[str, str]]:
    doc = _nlp(text)
    matches = matcher(doc)
    results = []

    for match_id, start, end in matches:
        lang_span = doc[start:end]
        # Search a window around the language name for proficiency
        window_start = max(start - 10, 0)
        window_end = min(end + 10, len(doc))
        context = doc[window_start:window_end].text

        prof_match = PROF_PATTERN.search(context)
        raw_prof = prof_match.group(1) if prof_match else None

        results.append({
            "name": lang_span.text,
            "proficiency": normalize_proficiency(raw_prof).value
        })

    # Remove duplicates preferring stronger proficiency
    unique = {}
    order = [LanguageProficiency.BASIC, LanguageProficiency.INTERMEDIATE, LanguageProficiency.FLUENT, LanguageProficiency.NATIVE]

    def prof_rank(prof):
        try:
            return order.index(LanguageProficiency(prof))
        except ValueError:
            return 0

    for entry in results:
        key = entry["name"].lower()
        if (key not in unique) or (prof_rank(entry["proficiency"]) > prof_rank(unique[key]["proficiency"])):
            unique[key] = entry

    return list(unique.values())


make it also work with french cvs and if LanguageProficiency is not mentioned in cv make it basic by default