# -*- coding: UTF-8 -*
##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
# See LICENSE
##############################################################################

import datetime
from threading import Thread

from flask import current_app, g
from flask_mail import Message

from app import mail
from app.models.departements import Departement
from app.models.config import ScoDocSiteConfig
from app.scodoc import sco_preferences


def send_async_email(app, msg):
    "Send an email, async"
    with app.app_context():
        mail.send(msg)


def send_email(
    subject: str,
    sender: str,
    recipients: list,
    text_body: str,
    html_body="",
    bcc=(),
    attachments=(),
):
    """
    Send an email. _All_ ScoDoc mails SHOULD be sent using this function.

    If html_body is specified, build a multipart message with HTML content,
    else send a plain text email.

    attachements: list of dict { 'filename', 'mimetype', 'data' }
    """
    msg = Message(subject, sender=sender, recipients=recipients, bcc=bcc)
    msg.body = text_body
    msg.html = html_body
    if attachments:
        for attachment in attachments:
            msg.attach(
                attachment["filename"], attachment["mimetype"], attachment["data"]
            )

    send_message(msg)


def send_message(msg: Message):
    """Send a message.
    All ScoDoc emails MUST be sent by this function.

    In mail debug mode, addresses are discarded and all mails are sent to the
    specified debugging address.
    """
    email_test_mode_address = False
    if hasattr(g, "scodoc_dept"):
        # on est dans un département, on peut accéder aux préférences
        email_test_mode_address = sco_preferences.get_preference(
            "email_test_mode_address"
        )
        if email_test_mode_address:
            # Mode spécial test: remplace les adresses de destination
            orig_to = msg.recipients
            orig_cc = msg.cc
            orig_bcc = msg.bcc
            msg.recipients = [email_test_mode_address]
            msg.cc = None
            msg.bcc = None
            msg.subject = "[TEST SCODOC] " + msg.subject
            msg.body = (
                f"""--- Message ScoDoc dérouté pour tests ---
Adresses d'origine:
 to : {orig_to}
 cc : {orig_cc}
 bcc: {orig_bcc}
---
            \n\n"""
                + msg.body
            )
    now = datetime.datetime.now()
    formatted_time = now.strftime("%Y-%m-%d %H:%M:%S") + ".{:03d}".format(
        now.microsecond // 1000
    )
    current_app.logger.info(
        f"""[{formatted_time}] email sent to{
            ' (mode test)' if email_test_mode_address else ''
        }: {msg.recipients}
        from sender {msg.sender}
        """
    )
    Thread(
        target=send_async_email, args=(current_app._get_current_object(), msg)
    ).start()


def get_from_addr(dept_acronym: str = None):
    """L'adresse "from" à utiliser pour envoyer un mail

    Si le departement est spécifié, ou si l'attribut `g.scodoc_dept`existe,
    prend le `email_from_addr` des préférences de ce département si ce champ
    est non vide.
    Sinon, utilise le paramètre global `email_from_addr`.
    Sinon, la variable de config `SCODOC_MAIL_FROM`.
    """
    dept_acronym = dept_acronym or getattr(g, "scodoc_dept", None)
    if dept_acronym:
        dept = Departement.query.filter_by(acronym=dept_acronym).first()
        if dept:
            from_addr = (
                sco_preferences.get_preference("email_from_addr", dept_id=dept.id) or ""
            ).strip()
            if from_addr:
                return from_addr
    return (
        ScoDocSiteConfig.get("email_from_addr")
        or current_app.config["SCODOC_MAIL_FROM"]
        or "none"
    )