"""
Email delivery via SMTP. Sends one report email per issue per subscriber,
in the subscriber's preferred format/design/language. Every send is logged.
"""
import smtplib
import datetime as dt
from email.message import EmailMessage
from .reporter import generate, CONTENT_TYPES
from ..config import config
from ..models import EmailLog


def _send_raw(to_email, subject, body_text, attachment=None,
              attach_name=None, attach_type=None):
    msg = EmailMessage()
    msg["From"] = config.SMTP_FROM
    msg["To"] = to_email
    msg["Subject"] = subject
    msg.set_content(body_text)
    if attachment is not None:
        maintype, subtype = (attach_type or "application/octet-stream").split("/", 1)
        msg.add_attachment(attachment, maintype=maintype, subtype=subtype,
                           filename=attach_name)
    with smtplib.SMTP(config.SMTP_HOST, config.SMTP_PORT, timeout=30) as s:
        if config.SMTP_USE_TLS:
            s.starttls()
        if config.SMTP_USER:
            s.login(config.SMTP_USER, config.SMTP_PASS)
        s.send_message(msg)


def send_issue_to_subscriber(session, issue, applications, subscriber, base_url=""):
    """Generate a report containing only the subscriber's watched classes and email it.
    Returns the EmailLog, or None if the subscriber has no matching applications."""
    fmt = subscriber.pref_format or "pdf"
    design = subscriber.pref_design or "bulletin"
    lang = subscriber.pref_language or "en"

    # Filter to the subscriber's classes of interest (None => all).
    watched = subscriber.watched_classes()
    matched = [a for a in applications if a.matches_classes(watched)]
    if not matched:
        return None  # nothing relevant for this subscriber; don't email

    watched_label = ("classes " + ", ".join(sorted(watched, key=lambda x: (len(x), x)))
                     if watched else "all classes")
    subject = f"Iran Trademark Applications — {issue.publication_date} — Daily Watch"
    body = (
        f"Dear {subscriber.name},\n\n"
        f"Please find attached the Iran Trademark Applications watch report "
        f"published on {issue.publication_date}.\n"
        f"Opposition deadline: {issue.opposition_deadline} "
        f"(30 days from publication).\n\n"
        f"This report covers {watched_label}.\n"
        f"Matching applications in this issue: {len(matched)} of {len(applications)}\n\n"
        f"Regards"
    )
    log = EmailLog(issue_id=issue.id, subscriber_id=subscriber.id,
                   to_email=subscriber.email, subject=subject, fmt=fmt)
    try:
        data = generate(issue, matched, fmt=fmt, design=design,
                        lang=lang, base_url=base_url)
        name = f"Iran_TM_{issue.publication_date}.{fmt}"
        _send_raw(subscriber.email, subject, body, attachment=data,
                  attach_name=name, attach_type=CONTENT_TYPES[fmt])
        log.status = "sent"
    except Exception as e:
        log.status = "failed"
        log.error = str(e)
    session.add(log)
    session.commit()
    return log


def send_issue_to_all(session, issue, applications, subscribers, base_url=""):
    results = {"sent": 0, "failed": 0, "skipped": 0, "logs": []}
    for sub in subscribers:
        if not sub.active:
            continue
        log = send_issue_to_subscriber(session, issue, applications, sub, base_url)
        if log is None:
            results["skipped"] += 1
        elif log.status == "sent":
            results["sent"] += 1
            results["logs"].append(log)
        else:
            results["failed"] += 1
            results["logs"].append(log)
    return results


def send_invoice(subscriber, invoice, pdf_bytes=None):
    subject = f"Invoice {invoice.number} — {invoice.period_start} to {invoice.period_end}"
    body = (
        f"Dear {subscriber.name},\n\n"
        f"Please find your invoice {invoice.number} for the period "
        f"{invoice.period_start} – {invoice.period_end}.\n"
        f"Amount due: {invoice.amount}\n\nRegards"
    )
    _send_raw(subscriber.email, subject, body,
              attachment=pdf_bytes,
              attach_name=f"{invoice.number}.pdf" if pdf_bytes else None,
              attach_type="application/pdf" if pdf_bytes else None)
