import smtplib
from email.message import EmailMessage
from email.utils import formataddr

from flask import current_app
from markupsafe import escape

from database import db
from models.project import Project
from models.user import User
from models.user_project import UserProject


def _project_recipients(project_id):
    """E-mails de todos os usuários associados ao projeto (via user_projects)."""
    users = (
        User.query.join(UserProject, UserProject.user_id == User.id)
        .filter(UserProject.project_id == project_id)
        .all()
    )
    return [u.email for u in users if u.email]


def _project_name(project_id):
    """Nome do projeto para o assunto do e-mail (fallback genérico se não achar)."""
    project = db.session.get(Project, project_id)
    return project.name if project else "Prumo"


def _build_html(actor_name, action, issue):
    """Compõe o corpo HTML da notificação."""
    actor = escape(actor_name or "Alguém")
    title = escape(issue.title or "")
    description = str(escape(issue.description or "")).replace("\n", "<br>")
    return (
        f"<p>O usuário {actor} {action} o ticket #{issue.id}.</p>"
        f"<h2>{title}</h2>"
        f"<p>{description}</p>"
        '<p style="text-align:center;font-size:0.8em;color:#888;margin-top:2em;">'
        "Esta é uma mensagem automática.<br>Não responda.</p>"
    )


def _build_message(recipients, actor_name, action, issue, project_name):
    """Monta o EmailMessage (texto + HTML) com a formatação do sistema."""
    msg = EmailMessage()
    msg["Subject"] = f"[{project_name}] Ticket {issue.id} - {issue.title}"
    msg["From"] = formataddr(("Prumo", current_app.config["MAIL_USERNAME"]))
    msg["To"] = ", ".join(recipients)
    msg.set_content(
        f"O usuário {actor_name or 'Alguém'} {action} o ticket #{issue.id}.\n\n"
        f"{issue.title}\n\n{issue.description or ''}\n\n"
        "—\nEsta é uma mensagem automática. Não responda."
    )
    msg.add_alternative(_build_html(actor_name, action, issue), subtype="html")
    return msg


def _send(msg):
    """Envia a mensagem via SMTP SSL. Levanta exceção em caso de falha."""
    server = current_app.config["MAIL_SERVER"]
    port = current_app.config["MAIL_PORT"]
    username = current_app.config["MAIL_USERNAME"]
    password = current_app.config.get("MAIL_PASSWORD")

    with smtplib.SMTP_SSL(server, port, timeout=15) as smtp:
        smtp.login(username, password)
        smtp.send_message(msg)


def send_issue_notification(issue, actor_name, action, project_id):
    """Envia a notificação de criação/alteração de um ticket a todos os usuários
    do projeto. Falhas de envio são logadas e não interrompem o fluxo."""
    recipients = _project_recipients(project_id)
    if not recipients:
        return

    msg = _build_message(recipients, actor_name, action, issue, _project_name(project_id))
    try:
        _send(msg)
    except Exception:
        current_app.logger.exception(
            "Falha ao enviar notificação do ticket #%s", issue.id
        )


class _SampleIssue:
    """Ticket fictício para o e-mail de teste, exercitando a formatação."""
    id = 0
    title = "Exemplo de título do ticket"
    description = (
        "Este é o texto normal do ticket, no corpo da mensagem.\n"
        "Ele pode ter várias linhas — cada quebra vira um <br> no e-mail."
    )


def send_test_email(recipient):
    """Envia um e-mail de teste com a mesma formatação das notificações reais.
    Levanta exceção se o envio falhar (para o comando CLI mostrar o erro)."""
    issue = _SampleIssue()
    msg = _build_message([recipient], "Ricardo (teste)", "criou", issue, _project_name(1))
    _send(msg)
