"""Module d'extraction et transformation du contenu des emails en discours."""

import re
import html2text
from bs4 import BeautifulSoup


class ContentExtractor:
    """Extrait et transforme le contenu HTML en texte parlable."""

    def __init__(self):
        self.html_converter = html2text.HTML2Text()
        self.html_converter.ignore_links = True
        self.html_converter.ignore_images = True
        self.html_converter.ignore_emphasis = False
        self.html_converter.body_width = 0

    def extract_text(self, html_content: str, plain_text: str = "") -> str:
        """Extrait le texte principal d'un email HTML."""
        if not html_content and plain_text:
            return self._clean_raw_text(plain_text)

        if not html_content:
            return ""

        soup = BeautifulSoup(html_content, "html.parser")
        self._remove_unwanted_elements(soup)
        cleaned_html = str(soup)
        text = self.html_converter.handle(cleaned_html)
        text = self._clean_raw_text(text)

        return text

    def _remove_unwanted_elements(self, soup: BeautifulSoup) -> None:
        """Supprime les éléments HTML indésirables."""
        unwanted_tags = ["script", "style", "head", "meta", "link", "noscript", "iframe"]
        for tag in unwanted_tags:
            for element in soup.find_all(tag):
                element.decompose()

        # Supprimer footers et éléments de désinscription
        unwanted_patterns = [
            r"se désinscrire", r"unsubscribe", r"désabonner",
            r"préférences d'email", r"view in browser", r"voir dans le navigateur",
            r"©\s*\d{4}", r"tous droits réservés", r"all rights reserved",
            r"politique de confidentialité", r"privacy policy",
        ]

        for element in soup.find_all(string=True):
            try:
                text_lower = str(element).lower() if element else ""
                for pattern in unwanted_patterns:
                    if re.search(pattern, text_lower, re.IGNORECASE):
                        if hasattr(element, 'parent') and element.parent:
                            parent = element.parent
                            if parent.name not in ["body", "html", "[document]"]:
                                parent.decompose()
                        break
            except Exception:
                continue

    def _clean_raw_text(self, text: str) -> str:
        """Nettoie le texte brut extrait."""
        # Supprimer URLs et emails
        text = re.sub(r"http[s]?://\S+", "", text)
        text = re.sub(r"www\.\S+", "", text)
        text = re.sub(r"<?\S+@\S+\.\S+>?", "", text)

        # Normaliser espaces
        text = re.sub(r"\n{3,}", "\n\n", text)
        text = re.sub(r"[ \t]+", " ", text)
        text = re.sub(r" +\n", "\n", text)
        text = re.sub(r"\n +", "\n", text)

        # Supprimer lignes sans contenu alphanumérique
        lines = text.split("\n")
        cleaned_lines = [line for line in lines if re.search(r"[a-zA-ZÀ-ÿ0-9]", line.strip())]
        text = "\n".join(cleaned_lines)

        return text.strip()

    def _remove_email_headers(self, text: str) -> str:
        """Supprime tous les headers d'email et de transfert."""
        # Supprimer les blocs "Forwarded Message"
        text = re.sub(r"-{3,}\s*Forwarded\s+Message\s*-{3,}", "", text, flags=re.IGNORECASE)
        text = re.sub(r"-{3,}\s*Forwarded\s+message\s*-{3,}", "", text, flags=re.IGNORECASE)

        # Supprimer les lignes de métadonnées email
        email_patterns = [
            r"^From:.*$",
            r"^To:.*$",
            r"^Sent:.*$",
            r"^Date:.*$",
            r"^Subject:.*$",
            r"^Cc:.*$",
            r"^Bcc:.*$",
            r"^Reply-To:.*$",
        ]
        for pattern in email_patterns:
            text = re.sub(pattern, "", text, flags=re.MULTILINE | re.IGNORECASE)

        # Supprimer les lignes vides multiples créées
        text = re.sub(r"\n{3,}", "\n\n", text)

        return text.strip()

    def _find_newsletter_content(self, text: str) -> str:
        """Trouve et extrait uniquement le contenu de la newsletter."""
        # Chercher "Au sommaire" comme début du vrai contenu
        start_markers = [
            r"Au sommaire",
            r"Briefing\s*■",
        ]

        for marker in start_markers:
            match = re.search(marker, text, re.IGNORECASE)
            if match:
                text = text[match.start():]
                break

        # Supprimer les lignes d'introduction répétitives
        text = re.sub(r"Chaque soir,\s*\d+\s*minutes[^.]*\.\s*", "", text, flags=re.IGNORECASE)
        text = re.sub(r"Lire la newsletter en ligne\.?\s*", "", text, flags=re.IGNORECASE)

        # Chercher la fin du contenu (avant les liens/footers)
        end_markers = [
            r"Merci de nous avoir lus",
            r"À demain",
            r"À bientôt",
            r"Bonne lecture",
        ]

        for marker in end_markers:
            match = re.search(marker, text, re.IGNORECASE)
            if match:
                text = text[:match.start()]  # Ne pas garder "Merci de nous avoir lus"
                break

        return text.strip()

    def _transform_to_discourse(self, text: str) -> str:
        """Transforme le texte structuré en discours naturel."""

        # Supprimer "Lire la newsletter en ligne" et similaires
        text = re.sub(r"Lire la newsletter en ligne\.?", "", text, flags=re.IGNORECASE)

        # Transformer "Briefing ■" en introduction
        text = re.sub(r"Briefing\s*■\.?", "", text)

        # Supprimer les dates en début de ligne (ex: "mardi 8 septembre 2026")
        text = re.sub(r"^(lundi|mardi|mercredi|jeudi|vendredi|samedi|dimanche)\s+\d{1,2}\s+\w+\s+\d{4}\.?",
                      "", text, flags=re.MULTILINE | re.IGNORECASE)

        # Transformer "Au sommaire •" en transition
        text = re.sub(r"Au sommaire\s*[•:]\s*", "Voici les sujets du jour : ", text, flags=re.IGNORECASE)

        # Supprimer "L'info." car redondant (gérer les deux types d'apostrophes)
        text = re.sub(r"L[''']info\.\s*", "", text)

        # Transformer "Les enjeux." en transition
        text = re.sub(r"\bLes enjeux\.\s*", "Les enjeux sont les suivants : ", text)

        # Transformer "En chiffres." en transition et traiter le premier bullet inline
        text = re.sub(r"En chiffres\.\s*\*\s*", "Voici les chiffres clés. ", text)
        text = re.sub(r"En chiffres\.\s*", "Voici les chiffres clés. ", text)

        # Transformer "Le graphique." ou "Le + de mind."
        text = re.sub(r"\bLe graphique\.\s*", "Concernant les données graphiques : ", text)
        text = re.sub(r"\bLe \+ de mind\.\s*", "Notre analyse : ", text)

        # Transformer "Plus de détails." en transition
        text = re.sub(r"Plus de détails\.\s*\*\s*", "Voici plus de détails. ", text)
        text = re.sub(r"Plus de détails\.\s*", "Voici plus de détails. ", text)

        # Supprimer "Signaux." comme titre de section
        text = re.sub(r"\n\s*Signaux\.\s*\n", "\n\n", text)

        # Supprimer "Repères & Performances" et similaires
        text = re.sub(r"\n\s*Repères & Performances\.?\s*\n", "\n", text)

        # Supprimer les noms d'auteurs isolés sur une ligne (ex: "Antoine Duroyon.")
        text = re.sub(r"\n\s*[A-Z][a-zéèêà]+\s+[A-Z][a-zéèêà]+\.\s*\n", "\n", text)

        # Supprimer "À lire également." et "Les liens du jour"
        text = re.sub(r"\n\s*À lire également\.\s*\n", "\n\nVoici d'autres actualités importantes.\n", text)
        text = re.sub(r"\n\s*Les liens du jour sélectionnés par la rédaction\.\s*\n", "\n", text)


        # Transformer "Les liens du jour sélectionnés par la rédaction."
        text = re.sub(r"Les liens du jour sélectionnés par la rédaction\.\s*",
                      "Voici une sélection de liens importants : ", text)

        # Transformer les bullets points "•" ou "*" en phrases fluides
        # D'abord, collecter toutes les lignes avec bullets et les transformer
        lines = text.split("\n")
        bullet_count = 0
        new_lines = []
        transitions = ["Premièrement,", "Deuxièmement,", "Troisièmement,", "Par ailleurs,", "Également,", "Enfin,"]

        for line in lines:
            if re.match(r"^\s*[•\*]\s*", line):
                clean_line = re.sub(r"^\s*[•\*]\s*", "", line)
                if bullet_count < len(transitions):
                    new_lines.append(f"{transitions[bullet_count]} {clean_line}")
                else:
                    new_lines.append(f"De plus, {clean_line}")
                bullet_count += 1
            else:
                new_lines.append(line)
                # Reset counter for new section
                if not line.strip():
                    bullet_count = 0

        text = "\n".join(new_lines)

        # Supprimer les emojis ou les remplacer par du texte
        emoji_replacements = {
            r"🤖": "Intelligence artificielle : ",
            r"💳": "Paiement : ",
            r"🏦": "Banque : ",
            r"📊": "Données : ",
            r"💰": "Finance : ",
            r"📈": "Croissance : ",
            r"👋": "",
        }
        for emoji, replacement in emoji_replacements.items():
            text = re.sub(emoji, replacement, text)

        # Supprimer les emojis restants
        text = re.sub(r"[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\U0001F680-\U0001F6FF\U0001F1E0-\U0001F1FF\U00002702-\U000027B0]+", "", text)

        # Transformer "J'explore les trackers." et boutons similaires
        text = re.sub(r"J'explore les trackers\.?", "", text, flags=re.IGNORECASE)

        # Nettoyer les parenthèses avec sources (Communiqué), (Reuters), etc.
        text = re.sub(r"\s*\([^)]*(?:Communiqué|Reuters|Bloomberg|AFP|Source)[^)]*\)", "", text, flags=re.IGNORECASE)

        # Transformer les tirets en virgules pour une lecture fluide
        text = re.sub(r"\s+,\s+", ", ", text)

        # Assurer que les phrases se terminent par un point
        lines = text.split("\n")
        formatted_lines = []
        for line in lines:
            line = line.strip()
            if line and not line.endswith((".", "!", "?", ":", ",")):
                line += "."
            formatted_lines.append(line)
        text = "\n".join(formatted_lines)

        # Supprimer les lignes vides multiples
        text = re.sub(r"\n{3,}", "\n\n", text)

        return text.strip()

    def _format_for_speech(self, text: str) -> str:
        """Formatage final pour la synthèse vocale."""

        # Normaliser les abréviations
        abbreviations = {
            r"\bM\.\s": "Monsieur ",
            r"\bMme\b": "Madame",
            r"\bMlle\b": "Mademoiselle",
            r"\bDr\b": "Docteur",
            r"\bPr\b": "Professeur",
            r"\bn°\s*": "numéro ",
            r"\bvs\.?\b": "versus",
            r"\betc\.": "et cetera",
            r"\b%": " pour cent",
            r"\bPME\b": "P M E",
            r"\bIA\b": "intelligence artificielle",
            r"\bAPI\b": "A P I",
            r"\bSCT\b": "S C T",
            r"\bIP\b": "I P",
            r"\bOSMP\b": "O S M P",
        }
        for abbr, full in abbreviations.items():
            text = re.sub(abbr, full, text)

        # Formater les grands nombres pour la lecture
        # Ex: "1,24 milliard" reste tel quel (déjà lisible)
        # Ex: "205,9 millions" reste tel quel

        # Ajouter des pauses (représentées par des points) après les sections importantes
        text = re.sub(r"(\. )(Voici|Passons|Concernant|Pour plus|Parmi)", r".\n\n\2", text)

        return text

    def to_speech_script(self, text: str, title: str = "") -> str:
        """Transforme le texte en script optimisé pour la lecture audio."""

        # Étape 1: Supprimer les headers d'email
        clean_text = self._remove_email_headers(text)

        # Étape 2: Extraire uniquement le contenu de la newsletter
        clean_text = self._find_newsletter_content(clean_text)

        # Étape 3: Transformer en discours naturel
        clean_text = self._transform_to_discourse(clean_text)

        # Étape 4: Formatage final pour TTS
        clean_text = self._format_for_speech(clean_text)

        # Construire le script final
        script_parts = []

        # Introduction
        if title:
            clean_title = self._clean_title_for_speech(title)
            script_parts.append(f"Bienvenue dans le briefing Mind Fintech.")
            script_parts.append(f"Au programme aujourd'hui : {clean_title}.")
            script_parts.append("")

        # Corps
        script_parts.append(clean_text)

        # Conclusion
        script_parts.append("")
        script_parts.append("C'était le briefing Mind Fintech du jour. À très bientôt pour la prochaine édition.")

        return "\n\n".join(script_parts)

    def _clean_title_for_speech(self, title: str) -> str:
        """Nettoie le titre pour la lecture orale."""
        prefixes = [
            r"^\[.*?\]\s*",
            r"^Fw:\s*",
            r"^Fwd:\s*",
            r"^RE:\s*",
            r"^FW:\s*",
            r"^Newsletter\s*[:\-]?\s*",
            r"^Briefing\s*[:\-]?\s*",
        ]
        for prefix in prefixes:
            title = re.sub(prefix, "", title, flags=re.IGNORECASE)

        # Remplacer | par "et"
        title = title.replace("|", " et ")
        title = re.sub(r"\s+", " ", title)

        return title.strip()

    def generate_title(self, subject: str, date: str = "") -> str:
        """Génère un titre pour la vidéo/podcast."""
        clean_title = self._clean_title_for_speech(subject)

        if date:
            date_match = re.search(r"(\d{1,2})\s+(\w+)\s+(\d{4})", date)
            if date_match:
                day, month, year = date_match.groups()
                clean_title = f"{clean_title} - {day} {month} {year}"

        if len(clean_title) > 95:
            clean_title = clean_title[:92] + "..."

        return clean_title

    def generate_description(self, text: str, max_length: int = 500) -> str:
        """Génère une description pour le podcast."""
        lines = [line.strip() for line in text.split("\n") if line.strip()]
        description = " ".join(lines[:5])

        if len(description) > max_length:
            description = description[:max_length - 3] + "..."

        description += "\n\n---\nPodcast généré automatiquement à partir de la newsletter Mind Fintech."

        return description
