import logging
from email.utils import getaddresses

from odoo import models

_logger = logging.getLogger(__name__)

PARAM = "xeno_mail_staging.redirect_to"
EXEMPT_PARAM = "xeno_mail_staging.exempt_emails"


class IrMailServer(models.Model):
    _inherit = "ir.mail_server"

    def send_email(self, message, *args, **kwargs):
        """Intercepts every outgoing email at the lowest common point (the
        built MIME message, right before SMTP), regardless of which model
        constructed it (mail.mail, password reset, digests, activity
        reminders, ...), and redirects To/Cc/Bcc to a single test address.
        Controlled purely by the xeno_mail_staging.redirect_to system
        parameter -- delete/blank it to stop redirecting, no code change
        or redeploy needed (e.g. before cutover).

        xeno_mail_staging.exempt_emails (comma-separated addresses) lets
        specific real recipients receive mail for real while everyone else
        still gets redirected -- e.g. an approver who now has a working
        Odoo login and needs to actually receive approval-step emails
        before the rest of the company is ready to. Only bypasses the
        redirect when EVERY recipient (To + Cc) of a given message is on
        the exempt list -- a message with any non-exempt recipient mixed
        in still gets redirected in full, rather than risk splitting a
        message or leaking it to someone not yet exempted.
        """
        redirect_to = self.env["ir.config_parameter"].sudo().get_param(PARAM)
        if redirect_to:
            exempt_raw = self.env["ir.config_parameter"].sudo().get_param(EXEMPT_PARAM) or ""
            exempt = {e.strip().lower() for e in exempt_raw.split(",") if e.strip()}
            if exempt:
                recipients = {
                    addr.lower() for _, addr in
                    getaddresses([message.get("To") or "", message.get("Cc") or ""])
                    if addr
                }
                if recipients and recipients <= exempt:
                    _logger.info(
                        "xeno_mail_staging: %s fully exempt from redirect, sending for real",
                        recipients,
                    )
                    return super().send_email(message, *args, **kwargs)
            original_to = message.get("To") or ""
            original_cc = message.get("Cc") or ""
            for header in ("To", "Cc", "Bcc"):
                if message[header] is not None:
                    del message[header]
            message["To"] = redirect_to

            if original_to and not message.get("X-Xeno-Original-To"):
                message["X-Xeno-Original-To"] = original_to
            if original_cc and not message.get("X-Xeno-Original-Cc"):
                message["X-Xeno-Original-Cc"] = original_cc

            subject = message.get("Subject", "") or ""
            if not subject.startswith("[STAGING"):
                del message["Subject"]
                message["Subject"] = "[STAGING - to: %s] %s" % (original_to or "?", subject)

            _logger.info(
                "xeno_mail_staging: redirected email (originally to %s) to %s",
                original_to, redirect_to,
            )
            # mail.mail's own _send() passes a 'send_validated_to' context
            # safety-list (the ORIGINAL recipients) that _prepare_smtp_to_list
            # filters against -- our redirected address isn't in it, so it
            # would otherwise get silently dropped and raise NO_VALID_RECIPIENT.
            # Since we've deliberately rewritten the recipient, that check no
            # longer applies here.
            return super(IrMailServer, self.with_context(send_validated_to=False)) \
                .send_email(message, *args, **kwargs)
        return super().send_email(message, *args, **kwargs)
