"""Module de filtrage et récupération des emails Gmail."""

import base64
from typing import Optional
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build

import config


class GmailFilter:
    """Gère la connexion Gmail et le filtrage des newsletters."""

    def __init__(self):
        self.service = None
        self.creds = None

    def authenticate(self) -> bool:
        """Authentification OAuth2 avec Gmail API."""
        self.creds = None

        # Charger le token existant s'il existe
        if config.TOKEN_FILE.exists():
            self.creds = Credentials.from_authorized_user_file(
                str(config.TOKEN_FILE), config.GMAIL_SCOPES
            )

        # Rafraîchir ou créer de nouvelles credentials
        if not self.creds or not self.creds.valid:
            if self.creds and self.creds.expired and self.creds.refresh_token:
                self.creds.refresh(Request())
            else:
                if not config.CREDENTIALS_FILE.exists():
                    raise FileNotFoundError(
                        f"Fichier credentials.json non trouvé: {config.CREDENTIALS_FILE}"
                    )
                flow = InstalledAppFlow.from_client_secrets_file(
                    str(config.CREDENTIALS_FILE), config.GMAIL_SCOPES
                )
                self.creds = flow.run_local_server(port=0)

            # Sauvegarder le token
            with open(config.TOKEN_FILE, "w") as token:
                token.write(self.creds.to_json())

        self.service = build("gmail", "v1", credentials=self.creds)
        return True

    def get_or_create_label(self, label_name: str) -> str:
        """Récupère ou crée un label Gmail."""
        results = self.service.users().labels().list(userId="me").execute()
        labels = results.get("labels", [])

        for label in labels:
            if label["name"] == label_name:
                return label["id"]

        # Créer le label s'il n'existe pas
        label_body = {
            "name": label_name,
            "labelListVisibility": "labelShow",
            "messageListVisibility": "show",
        }
        created = (
            self.service.users().labels().create(userId="me", body=label_body).execute()
        )
        return created["id"]

    def get_unprocessed_newsletters(self, max_results: int = 10) -> list[dict]:
        """Récupère les emails non traités contenant l'adresse de la newsletter."""
        if not self.service:
            raise RuntimeError("Non authentifié. Appelez authenticate() d'abord.")

        # Construire la requête de recherche
        query = f"from:{config.GMAIL_FILTER_ADDRESS} OR {config.GMAIL_FILTER_ADDRESS}"
        query += f" -label:{config.PROCESSED_LABEL}"

        results = (
            self.service.users()
            .messages()
            .list(userId="me", q=query, maxResults=max_results)
            .execute()
        )

        messages = results.get("messages", [])
        emails = []

        for msg in messages:
            email_data = self.get_email_content(msg["id"])
            if email_data:
                emails.append(email_data)

        return emails

    def get_email_content(self, message_id: str) -> Optional[dict]:
        """Récupère le contenu complet d'un email."""
        msg = (
            self.service.users()
            .messages()
            .get(userId="me", id=message_id, format="full")
            .execute()
        )

        headers = msg.get("payload", {}).get("headers", [])
        subject = ""
        sender = ""
        date = ""

        for header in headers:
            name = header.get("name", "").lower()
            if name == "subject":
                subject = header.get("value", "")
            elif name == "from":
                sender = header.get("value", "")
            elif name == "date":
                date = header.get("value", "")

        # Extraire le corps de l'email
        body_html = ""
        body_text = ""

        payload = msg.get("payload", {})
        body_html, body_text = self._extract_body(payload)

        return {
            "id": message_id,
            "subject": subject,
            "sender": sender,
            "date": date,
            "body_html": body_html,
            "body_text": body_text,
        }

    def _extract_body(self, payload: dict) -> tuple[str, str]:
        """Extrait le corps HTML et texte d'un payload email."""
        body_html = ""
        body_text = ""

        mime_type = payload.get("mimeType", "")

        if mime_type == "text/html":
            data = payload.get("body", {}).get("data", "")
            if data:
                body_html = base64.urlsafe_b64decode(data).decode("utf-8", errors="ignore")
        elif mime_type == "text/plain":
            data = payload.get("body", {}).get("data", "")
            if data:
                body_text = base64.urlsafe_b64decode(data).decode("utf-8", errors="ignore")
        elif "multipart" in mime_type:
            parts = payload.get("parts", [])
            for part in parts:
                html, text = self._extract_body(part)
                if html:
                    body_html = html
                if text:
                    body_text = text

        return body_html, body_text

    def mark_as_processed(self, message_id: str) -> bool:
        """Marque un email comme traité en ajoutant le label."""
        label_id = self.get_or_create_label(config.PROCESSED_LABEL)

        self.service.users().messages().modify(
            userId="me",
            id=message_id,
            body={"addLabelIds": [label_id]},
        ).execute()

        return True

    def unmark_as_processed(self, message_id: str) -> bool:
        """Retire le label 'traité' d'un email pour le retraiter."""
        try:
            label_id = self.get_or_create_label(config.PROCESSED_LABEL)
            self.service.users().messages().modify(
                userId="me",
                id=message_id,
                body={"removeLabelIds": [label_id]},
            ).execute()
            return True
        except Exception:
            return False

    def list_newsletters(self, max_results: int = 5) -> list[dict]:
        """Liste les newsletters récentes (pour test/debug)."""
        if not self.service:
            raise RuntimeError("Non authentifié. Appelez authenticate() d'abord.")

        query = f"from:{config.GMAIL_FILTER_ADDRESS} OR {config.GMAIL_FILTER_ADDRESS}"

        results = (
            self.service.users()
            .messages()
            .list(userId="me", q=query, maxResults=max_results)
            .execute()
        )

        messages = results.get("messages", [])
        summaries = []

        for msg in messages:
            msg_data = (
                self.service.users()
                .messages()
                .get(userId="me", id=msg["id"], format="metadata")
                .execute()
            )
            headers = msg_data.get("payload", {}).get("headers", [])
            subject = next(
                (h["value"] for h in headers if h["name"].lower() == "subject"),
                "Sans sujet",
            )
            date = next(
                (h["value"] for h in headers if h["name"].lower() == "date"),
                "Date inconnue",
            )
            summaries.append({"id": msg["id"], "subject": subject, "date": date})

        return summaries
