ami uisng the best model to extract experience ? from datetime import datetime
from typing import List, Optional
import re
from dateutil import parser as date_parser
from langdetect import detect
from transformers import pipeline
from cvs_manager.models import ExperienceType
from cvs_manager.schemas import _ExperienceBase


# Multilingual NER handler
class MultilingualNER:
    def __init__(self):
        self._ner_en = None
        self._ner_fr = None

    def get_pipeline(self, lang: str):
        if lang == "fr":
            if not self._ner_fr:
                print("[ExperienceExtractor] Loading French NER model...")
                self._ner_fr = pipeline(
                    "ner",
                    model="gilf/french-camembert-large-fquad-piaf-ner",
                    tokenizer="gilf/french-camembert-large-fquad-piaf-ner",
                    aggregation_strategy="simple"
                )
            return self._ner_fr
        else:
            if not self._ner_en:
                print("[ExperienceExtractor] Loading English NER model...")
                self._ner_en = pipeline(
                    "ner",
                    model="Jean-Baptiste/roberta-large-ner-english",
                    tokenizer="Jean-Baptiste/roberta-large-ner-english",
                    aggregation_strategy="simple"
                )
            return self._ner_en

    def __call__(self, text: str):
        try:
            lang = detect(text)
        except Exception:
            lang = "en"  # default to english on detection failure
        return self.get_pipeline(lang)(text)


_multilingual_ner = MultilingualNER()

# -------------------- Section Extraction --------------------

def extract_work_experience_section(text: str) -> str:
    section_patterns = [
        r"(WORK EXPERIENCE|EXPERIENCE|EMPLOYMENT|PROFESSIONAL EXPERIENCE|PROFESSIONAL HISTORY)(.*?)(?:\n[A-Z ]{3,}|$)",
        r"(INTERNSHIPS|INTERNSHIP)(.*?)(?:\n[A-Z ]{3,}|$)",
        r"(PROJECTS|PERSONAL PROJECTS)(.*?)(?:\n[A-Z ]{3,}|$)"
    ]
    for pattern in section_patterns:
        match = re.search(pattern, text, re.DOTALL | re.IGNORECASE)
        if match:
            return match.group(2).strip()
    return text

def split_experience_entries(section_text: str) -> List[str]:
    entries = re.split(r"\n{2,}", section_text)
    return [e.strip() for e in entries if len(e.strip()) > 30]

# -------------------- Field Extractors --------------------

def extract_job_title(text: str) -> str:
    ner_results = _multilingual_ner(text)
    candidates = [ent['word'] for ent in ner_results if ent['entity_group'] in ['MISC']]
    if candidates:
        return max(candidates, key=len)
    match = re.match(r"^(.*?)(?: at | with | in | - |,|$)", text)
    if match:
        title = match.group(1).strip()
        if len(title) < 2 or re.search(r"\d{4}", title):
            return "Unknown"
        return title
    return "Unknown"

def extract_company(text: str) -> str:
    ner_results = _multilingual_ner(text)
    companies = [ent['word'] for ent in ner_results if ent['entity_group'] == 'ORG']
    if companies:
        return max(companies, key=len)
    match = re.search(r"(?: at | of )([A-Za-z0-9& ,.\-]+)", text)
    if match:
        return match.group(1).strip()
    return "Unknown"

def extract_dates(text: str) -> (Optional[datetime], Optional[datetime]): # type: ignore
    date_patterns = [
        r"(Present|\b\d{1,2}/\d{4}\b|\b\d{4}\b|\b(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*[ ,.-]*\d{4})"
    ]
    dates_found = []
    for pattern in date_patterns:
        found = re.findall(pattern, text, re.IGNORECASE)
        dates_found.extend(found)

    dates_found = list(dict.fromkeys(dates_found))  # unique
    start_date = None
    end_date = None

    def parse_date_str(s: str) -> Optional[datetime]:
        s = s.strip()
        if s.lower() == "present":
            return None
        try:
            return date_parser.parse(s, fuzzy=True, default=datetime(1900,1,1))
        except Exception:
            return None

    if dates_found:
        start_date = parse_date_str(dates_found[0])
        if len(dates_found) > 1:
            end_date = parse_date_str(dates_found[1])
        else:
            end_date = None
    return start_date, end_date

def extract_key_skills(text: str) -> List[str]:
    ner_results = _multilingual_ner(text)
    skills_candidates = set(ent['word'] for ent in ner_results if ent['entity_group'] in ['MISC', 'ORG'])

    predefined_tech_stack = {
        "Python", "Django", "Flask", "SQL", "JavaScript", "React", "Node", "C++", "Java", "HTML", "CSS",
        "FastAPI", "Git", "Docker", "Kubernetes", "AWS", "Linux", "REST", "GraphQL", "MongoDB", "PostgreSQL"
    }
    lower_text = text.lower()
    skills = {s for s in predefined_tech_stack if s.lower() in lower_text}
    combined_skills = skills.union(skills_candidates)
    filtered_skills = [skill for skill in combined_skills if len(skill) > 1]
    return list(filtered_skills)

def extract_description(text: str) -> str:
    return text.strip() or "No description found."

def extract_type(text: str) -> ExperienceType:
    lowered = text.lower()
    if any(k in lowered for k in ["intern", "internship", "trainee", "research", "student"]):
        return ExperienceType.INTERN
    if any(k in lowered for k in ["freelance", "contract"]):
        return ExperienceType.CONTRACT
    return ExperienceType.PROFESSIONAL

# -------------------- Main Extraction Function --------------------

def extract_experiences_from_text(text: str, candidate_id: int) -> List[_ExperienceBase]:
    section_text = extract_work_experience_section(text)
    entries = split_experience_entries(section_text)
    experiences: List[_ExperienceBase] = []

    for entry in entries:
        job_title = extract_job_title(entry)
        company = extract_company(entry)
        start_date, end_date = extract_dates(entry)
        key_skills = extract_key_skills(entry)
        description = extract_description(entry)
        exp_type = extract_type(entry)

        experiences.append(
            _ExperienceBase(
                candidate_id=candidate_id,
                job_title=job_title,
                company=company,
                type=exp_type,
                key_skills=key_skills,
                start_date=start_date,
                end_date=end_date,
                description=description
            )
        )
    return experiences