"""Email configuration and delivery."""
import os
import re
import threading
from html import escape

from nexora.config import ADMIN_EMAIL, EMAIL_SENDING_ENABLED, SMTP_TIMEOUT_SECONDS, logger
from nexora.database.connection import db, execute, query


# ────────────────────────────────────────────────
# SMTP config
# ────────────────────────────────────────────────
def email_config():
    settings = query("SELECT contact_email, contact_phone FROM settings WHERE id = 1", one=True)
    contact_email = (settings["contact_email"] if settings and "contact_email" in settings.keys() else "") or ADMIN_EMAIL
    contact_phone = (settings["contact_phone"] if settings and "contact_phone" in settings.keys() else "") or "+92 331 0314962"
    host = os.environ.get("SMTP_HOST", "").strip()
    user = os.environ.get("SMTP_USER", "").strip()
    password = os.environ.get("SMTP_PASSWORD", "")
    from_email = (os.environ.get("SMTP_FROM_EMAIL", "").strip() or user).strip()
    return {
        "host": host,
        "port": int(os.environ.get("SMTP_PORT", "587")),
        "user": user,
        "password": password,
        "from_email": from_email,
        "from_name": os.environ.get("SMTP_FROM_NAME", "Nexora Esports"),
        "admin_email": contact_email.strip(),
        "contact_phone": contact_phone.strip(),
        "enabled": (
            EMAIL_SENDING_ENABLED
            and bool(host)
            and bool(user)
            and bool(password)
            and bool(from_email)
        ),
    }


def email_config_error():
    """Return a human-readable reason email delivery is unavailable."""
    cfg = email_config()
    missing = []
    if not EMAIL_SENDING_ENABLED:
        missing.append("EMAIL_SENDING_ENABLED is not 1, or the From domain is blocked by PUBLIC_SITE_DOMAIN alignment")
    for key, label in (
        ("host", "SMTP_HOST"),
        ("user", "SMTP_USER"),
        ("password", "SMTP_PASSWORD"),
        ("from_email", "SMTP_FROM_EMAIL"),
    ):
        if not cfg.get(key):
            missing.append(f"{label} is empty")
    return "; ".join(missing)


def email_plain_text(html_body):
    """Small HTML-to-text fallback so mail clients see a normal multipart email."""
    text = re.sub(r"(?i)<br\s*/?>", "\n", html_body or "")
    text = re.sub(r"(?i)</td\s*>", "  ", text)
    text = re.sub(r"(?i)</tr\s*>", "\n", text)
    text = re.sub(r"(?i)</p\s*>", "\n\n", text)
    text = re.sub(r"<[^>]+>", "", text)
    text = (
        text.replace("&nbsp;", " ")
        .replace("&amp;", "&")
        .replace("&lt;", "<")
        .replace("&gt;", ">")
        .replace("&mdash;", "-")
        .replace("&#x27;", "'")
    )
    lines = [re.sub(r"\s+", " ", line).strip() for line in text.splitlines()]
    return "\n".join(line for line in lines if line).strip()


# ────────────────────────────────────────────────
# Legacy simple email builder (kept for backward compat)
# ────────────────────────────────────────────────
def ticket_email_html(player_name, event_title, ticket_number, game_name, fee_label, fee_amount, total_payable, extra_note=""):
    """Clean transactional ticket email, intentionally short and non-promotional."""
    player_name = player_name or "Participant"
    event_title = event_title or "Nexora Esports Championship"
    ticket_number = ticket_number or ""
    game_name = game_name or "N/A"
    fee_label = fee_label or "Fee"
    fee_amount = fee_amount or "Rs. 0"
    total_payable = total_payable or "Rs. 0"
    note_html = f"<p>{extra_note}</p>" if extra_note else ""
    return f"""<!doctype html>
<html>
<body style="margin:0;padding:0;background:#f5f7fb;color:#111827;font-family:Arial,Helvetica,sans-serif;">
  <div style="max-width:600px;margin:0 auto;padding:24px;">
    <div style="background:#ffffff;border:1px solid #e5e7eb;border-radius:8px;padding:22px;">
      <h1 style="margin:0 0 14px;font-size:20px;line-height:1.35;color:#111827;">{event_title}</h1>
      <p style="margin:0 0 14px;font-size:14px;line-height:1.6;">Dear {player_name},</p>
      <p style="margin:0 0 14px;font-size:14px;line-height:1.6;">Your registration ticket is attached as a PDF.</p>
      <table role="presentation" width="100%" cellspacing="0" cellpadding="0" style="border-collapse:collapse;margin:16px 0;font-size:14px;">
        <tr><td style="padding:8px;border:1px solid #e5e7eb;background:#f9fafb;font-weight:bold;">Ticket ID</td><td style="padding:8px;border:1px solid #e5e7eb;">{ticket_number}</td></tr>
        <tr><td style="padding:8px;border:1px solid #e5e7eb;background:#f9fafb;font-weight:bold;">Game</td><td style="padding:8px;border:1px solid #e5e7eb;">{game_name}</td></tr>
        <tr><td style="padding:8px;border:1px solid #e5e7eb;background:#f9fafb;font-weight:bold;">{fee_label}</td><td style="padding:8px;border:1px solid #e5e7eb;">{fee_amount}</td></tr>
        <tr><td style="padding:8px;border:1px solid #e5e7eb;background:#f9fafb;font-weight:bold;">Total</td><td style="padding:8px;border:1px solid #e5e7eb;">{total_payable}</td></tr>
      </table>
      {note_html}
      <p style="margin:0 0 14px;font-size:14px;line-height:1.6;">Please bring this ticket with you at event entry.</p>
      <p style="margin:18px 0 0;font-size:14px;line-height:1.6;">Regards,<br><strong>Nexora Esports Team</strong></p>
    </div>
    <p style="margin:14px 0 0;text-align:center;font-size:12px;line-height:1.5;color:#6b7280;">You are receiving this email because you registered for {event_title}.</p>
  </div>
</body>
</html>"""


# ────────────────────────────────────────────────
# Status-specific email subject
# ────────────────────────────────────────────────
STATUS_SUBJECTS = {
    "under_verification": "Nexora Esports registration received",
    "paid":              "Nexora Esports payment confirmed",
    "unpaid":            "Nexora Esports payment pending",
    "rejected":          "Nexora Esports payment could not be verified",
    "cancelled":         "Nexora Esports registration cancelled",
    "refunded":          "Nexora Esports payment refunded",
}

STATUS_DISPLAY = {
    "under_verification": "Under Verification",
    "paid":              "Paid / Verified",
    "unpaid":            "Unpaid",
    "rejected":          "Rejected",
    "cancelled":         "Cancelled",
    "refunded":          "Refunded",
}


def status_email_subject(status):
    """Return a clean subject line for the given payment status key."""
    s = (status or "").lower().replace(" ", "_")
    return STATUS_SUBJECTS.get(s, "Nexora Esports registration update")


def _status_message_html(status, game_name, reason=""):
    """Return the status-specific paragraph — plain, transactional, no marketing."""
    s = (status or "").lower().replace(" ", "_")
    game_name = escape(game_name or "the event")
    reason = escape(reason or "")

    if s == "under_verification":
        return (
            f"Thank you for registering for <strong>{game_name}</strong>. "
            "Your registration has been received. Your payment proof is now "
            "<strong>under verification</strong>. Our team will review it and update your status."
        )
    elif s == "paid":
        return (
            f"Good news. Your payment for <strong>{game_name}</strong> is confirmed. "
            "Your registration is now <strong>paid and verified</strong>. Your PDF ticket is attached."
        )
    elif s == "unpaid":
        return (
            f"Your registration for <strong>{game_name}</strong> is currently marked "
            "<strong>unpaid</strong>. Please complete the payment and share valid proof for verification."
        )
    elif s == "rejected":
        reason_html = f"<br><br><strong>Reason:</strong> {reason}" if reason else ""
        return (
            f"The payment for your <strong>{game_name}</strong> registration could not be verified."
            f"{reason_html}<br><br>"
            f"Please submit the correct payment details."
        )
    elif s == "cancelled":
        reason_html = f"<br><br><strong>Reason:</strong> {reason}" if reason else ""
        return (
            f"Your registration for <strong>{game_name}</strong> has been cancelled."
            f"{reason_html}"
        )
    elif s == "refunded":
        return (
            f"Your payment for <strong>{game_name}</strong> has been refunded."
        )
    else:
        return (
            f"Your registration status for <strong>{game_name}</strong> has been updated "
            f"to <strong>{status.replace('_', ' ').title()}</strong>."
        )


def _pdf_note_for_status(status):
    """Return the PDF attachment note shown below the tables."""
    s = (status or "").lower().replace(" ", "_")
    if s == "under_verification":
        return 'Your PDF ticket is attached, but entry becomes valid only after payment approval.'
    elif s == "paid":
        return (
            'Your updated PDF ticket is attached. This ticket is marked '
            '"<strong>PAYMENT VERIFIED - VALID FOR ENTRY</strong>". '
            'Please keep it safe and bring it with you.'
        )
    elif s == "rejected":
        return (
            'The attached PDF ticket is marked '
            '"<strong>PAYMENT REJECTED - NOT VALID FOR ENTRY</strong>".'
        )
    elif s == "cancelled":
        return (
            'The attached PDF ticket is marked '
            '"<strong>REGISTRATION CANCELLED - NOT VALID FOR ENTRY</strong>".'
        )
    elif s == "refunded":
        return (
            'The attached PDF ticket is marked '
            '"<strong>PAYMENT REFUNDED - NOT VALID FOR ENTRY</strong>".'
        )
    else:
        return 'Your PDF ticket is attached to this email.'


def _table_row(label, value):
    """Single key-value row for the email tables."""
    value = escape(str(value or "Not provided"))
    return (
        f'<tr>'
        f'<td style="padding:8px 12px;border:1px solid #e5e7eb;background:#f9fafb;font-weight:bold;width:38%;">{escape(str(label))}</td>'
        f'<td style="padding:8px 12px;border:1px solid #e5e7eb;">{value}</td>'
        f'</tr>'
    )


def _section(title, rows):
    rows = [row for row in rows if row]
    if not rows:
        return ""
    return f"""
      <h2 style="margin:24px 0 10px;font-size:16px;line-height:1.35;color:#111827;">{escape(title)}</h2>
      <table role="presentation" width="100%" cellspacing="0" cellpadding="0"
             style="border-collapse:collapse;margin:0 0 12px;font-size:14px;">
        {''.join(rows)}
      </table>
    """


def _status_badge(status_label, status_key):
    colors = {
        "paid": ("#ecfdf5", "#047857", "#a7f3d0"),
        "under_verification": ("#fffbeb", "#b45309", "#fde68a"),
        "unpaid": ("#fef2f2", "#b91c1c", "#fecaca"),
        "rejected": ("#fef2f2", "#b91c1c", "#fecaca"),
        "cancelled": ("#f3f4f6", "#374151", "#d1d5db"),
        "refunded": ("#eff6ff", "#1d4ed8", "#bfdbfe"),
    }
    bg, fg, border = colors.get(status_key, ("#f3f4f6", "#374151", "#d1d5db"))
    return (
        f'<span style="display:inline-block;padding:7px 12px;border-radius:999px;'
        f'background:{bg};color:{fg};border:1px solid {border};font-size:12px;'
        f'font-weight:bold;letter-spacing:.02em;text-transform:uppercase;">'
        f'{escape(status_label)}</span>'
    )


def build_status_email_html(details, status, recipient_name=None, event_title=None, reason=""):
    """Build a comprehensive, status-specific email body.

    Parameters
    ----------
    details : dict
        The full registration details dict from ``registration_details()``.
    status : str
        The payment status key (e.g. ``'paid'``, ``'under_verification'``).
    recipient_name : str | None
        Name to use in greeting (defaults to details['name']).
    event_title : str | None
        Event title from settings.
    reason : str
        Optional admin reason for rejection/cancellation.
    """
    cfg = email_config()
    support_email = cfg.get("admin_email") or "nexora.esport.support@gmail.com"
    support_phone = cfg.get("contact_phone") or "+92 331 0314962"

    player_name = escape(recipient_name or details.get("name") or "Participant")
    event_title = escape(event_title or "Nexora Esports Championship")
    game_name = details.get("game") or "N/A"
    s = (status or "").lower().replace(" ", "_")
    status_label = STATUS_DISPLAY.get(s, status.replace("_", " ").title())

    # ── Key details (ticket # & amount) ──
    reg_id = f"NX-{int(details.get('id', 0)):04d}"
    ticket_number = details.get("ticket_number") or reg_id
    total_payable = details.get("total_payable") or details.get("snapshot_original") or "Rs. 0"
    amount_paid = details.get("amount_paid") or ("Rs. 0" if s != "paid" else total_payable)
    remaining_amount = details.get("remaining_amount") or ("Rs. 0" if s == "paid" else total_payable)
    discount_amount = details.get("snapshot_discount") or details.get("base_discount_amount") or "Rs. 0"
    original_amount = details.get("snapshot_original") or details.get("original_price") or total_payable
    fee_breakdown = details.get("fee_breakdown") or ""
    event_when = " ".join(
        part for part in (
            details.get("game_date") or "",
            details.get("game_time") or "",
        )
        if part
    ) or "Announced by admin"
    venue = details.get("game_venue") or details.get("game_venue_address") or "Announced by admin"

    # ── Status message ──
    status_msg = _status_message_html(s, game_name, reason)
    pdf_note = _pdf_note_for_status(s)

    registration_rows = [
        _table_row("Ticket Number", ticket_number),
        _table_row("Registration ID", details.get("ref") or reg_id),
        _table_row("Player Name", details.get("name")),
        _table_row("Email", details.get("email")),
        _table_row("Phone", details.get("phone")),
        _table_row("CNIC", details.get("cnic")),
        _table_row("Institution", details.get("university")),
        _table_row("Roll No", details.get("roll_no")),
    ]

    game_rows = [
        _table_row("Game", game_name),
        _table_row("Platform", details.get("platform")),
        _table_row("Entry Type", details.get("entry_type")),
        _table_row("Team / Nick Name", details.get("team_name")),
        _table_row("Leader", details.get("leader_name")),
        _table_row("Players", details.get("member_count")),
        _table_row("Event Date / Time", event_when),
        _table_row("Venue", venue),
    ]

    payment_rows = [
        _table_row("Payment Status", status_label),
        _table_row("Payment Method", details.get("payment_method")),
        _table_row("Original Amount", original_amount),
        _table_row("Discount", discount_amount),
        _table_row("Total Payable", total_payable),
        _table_row("Amount Paid", amount_paid),
        _table_row("Remaining Amount", remaining_amount),
        _table_row("Transaction Reference", details.get("transaction_reference")),
    ]

    qualifier_html = ""
    qualifier_pricing = details.get("qualifier_pricing") or {}
    qualifier_items = qualifier_pricing.get("items") or []
    if details.get("qualifier_count") or qualifier_items:
        qualifier_rows = [
            _table_row("Selected Qualifiers", details.get("qualifier_count")),
            _table_row("Qualifier Fee", details.get("qualifier_fee") or qualifier_pricing.get("total_fee")),
        ]
        for item in qualifier_items:
            qualifier_rows.append(_table_row(
                item.get("name") or "Qualifier",
                f"{item.get('original_fee', '')} - {item.get('discount_fee', 'Rs. 0')} discount = {item.get('final_fee', '')}",
            ))
        qualifier_html = _section("Qualifier Details", qualifier_rows)

    roster_html = ""
    roster = (details.get("team_roster") or "").strip()
    if roster and roster != "Individual player":
        roster_html = (
            '<h2 style="margin:24px 0 10px;font-size:16px;line-height:1.35;color:#111827;">Team Roster</h2>'
            f'<pre style="margin:0 0 12px;padding:12px;background:#f9fafb;border:1px solid #e5e7eb;'
            f'white-space:pre-wrap;font-family:Arial,Helvetica,sans-serif;font-size:13px;line-height:1.55;">'
            f'{escape(roster)}</pre>'
        )

    # Physical address for CAN-SPAM / GDPR compliance
    physical_address = "Nexora Esports, Pakistan"
    inbox_note = (
        "Kindly check your Inbox, Promotions, or Spam folder for future registration updates. "
        "If this email appears in Spam, please mark it as Not spam so you continue receiving ticket updates."
    )

    return f"""<!doctype html>
<html>
<body style="margin:0;padding:0;background:#f4f6fb;color:#111827;font-family:Arial,Helvetica,sans-serif;">
  <div style="max-width:720px;margin:0 auto;padding:24px;">
    <div style="background:#111827;color:#ffffff;padding:22px 24px;">
      <p style="margin:0 0 8px;font-size:13px;color:#fbbf24;font-weight:bold;">{event_title}</p>
      <h1 style="margin:0;font-size:24px;line-height:1.3;">Registration Update</h1>
      <div style="margin-top:14px;">{_status_badge(status_label, s)}</div>
    </div>
    <div style="background:#ffffff;border:1px solid #e5e7eb;border-top:none;padding:24px;">

      <p style="margin:0 0 14px;font-size:15px;line-height:1.6;">Assalam o Alaikum / Dear {player_name},</p>

      <p style="margin:0 0 20px;font-size:15px;line-height:1.7;">{status_msg}</p>

      <div style="background:#f9fafb;border:1px solid #e5e7eb;padding:14px;margin:0 0 18px;">
        <p style="margin:0;font-size:14px;line-height:1.6;">
          <strong>Game:</strong> {escape(str(game_name))}<br>
          <strong>Ticket:</strong> {escape(str(ticket_number))}<br>
          <strong>Total Payable:</strong> {escape(str(total_payable))}
        </p>
      </div>

      {_section("Registration Information", registration_rows)}
      {_section("Game Information", game_rows)}
      {_section("Payment Breakdown", payment_rows)}
      {qualifier_html}
      {roster_html}

      {f'<p style="margin:18px 0 0;font-size:14px;line-height:1.6;"><strong>Fee Note:</strong> {escape(fee_breakdown)}</p>' if fee_breakdown else ''}

      <p style="margin:20px 0 14px;font-size:14px;line-height:1.6;color:#374151;">{pdf_note}</p>

      <div style="background:#fff7ed;border:1px solid #fed7aa;padding:12px;margin:18px 0 0;">
        <p style="margin:0;font-size:13px;line-height:1.6;color:#7c2d12;">{inbox_note}</p>
      </div>

      <p style="margin:24px 0 0;font-size:14px;line-height:1.6;">
        Regards,<br>Nexora Esports Team
      </p>

      <hr style="margin:24px 0 16px;border:none;border-top:1px solid #e5e7eb;">
      <p style="margin:0;font-size:12px;line-height:1.5;color:#9ca3af;">
        Contact: {support_email} | {support_phone}<br>
        {physical_address}
      </p>
    </div>
  </div>
</body>
</html>"""


# ────────────────────────────────────────────────
# SMTP sender
# ────────────────────────────────────────────────
def _send_smtp_email(to_email, subject, html_body, attachments=None, cc_emails=None, all_recipients=None):
    """Send email via SMTP. Returns (ok, error_message).

    Supports both port 465 (implicit SSL) and port 587 (STARTTLS).
    """
    cfg = email_config()
    if not cfg.get("enabled") or not cfg.get("host"):
        reason = email_config_error() or "Email sending is not configured."
        logger.warning("SMTP send skipped for %s: %s", to_email, reason)
        return False, reason
    try:
        import smtplib
        from email.mime.multipart import MIMEMultipart
        from email.mime.text import MIMEText
        from email.mime.application import MIMEApplication
        from email.utils import formataddr, formatdate, make_msgid
        msg = MIMEMultipart("mixed")
        msg["From"] = formataddr((cfg.get("from_name", "Nexora Esports"), cfg["from_email"]))
        msg["To"] = to_email
        if cc_emails:
            msg["Cc"] = ", ".join(cc_emails)
        msg["Subject"] = subject
        msg["Date"] = formatdate(localtime=True)
        msg["Message-ID"] = make_msgid(domain=cfg["from_email"].split("@")[-1])
        msg["Reply-To"] = cfg.get("admin_email") or cfg["from_email"]
        msg["X-Mailer"] = "Nexora Esports Registration System"
        msg["Return-Path"] = cfg["from_email"]
        # Transactional markers: personalized one-to-one registration mail.
        # Avoid bulk/list headers so mailbox providers do not treat it as a campaign.
        msg["Feedback-ID"] = "registration:transactional:nexora"
        msg["X-Auto-Response-Suppress"] = "All"
        msg["Auto-Submitted"] = "auto-generated"
        body = MIMEMultipart("alternative")
        body.attach(MIMEText(email_plain_text(html_body), "plain", "utf-8"))
        body.attach(MIMEText(html_body, "html", "utf-8"))
        msg.attach(body)
        for fname, fdata in (attachments or []):
            part = MIMEApplication(fdata, _subtype="pdf")
            part.add_header("Content-Disposition", "attachment", filename=fname)
            msg.attach(part)
        port = int(cfg.get("port", 587) or 587)
        send_to = all_recipients or ([to_email] + (cc_emails or []))
        if port == 465:
            with smtplib.SMTP_SSL(cfg["host"], port, timeout=SMTP_TIMEOUT_SECONDS) as server:
                if cfg.get("user") and cfg.get("password"):
                    try:
                        server.login(cfg["user"], cfg["password"])
                    except Exception as le:
                        logger.warning("SMTP login warning (465): %s", le)
                server.sendmail(cfg["from_email"], send_to, msg.as_string())
        else:
            with smtplib.SMTP(cfg["host"], port, timeout=SMTP_TIMEOUT_SECONDS) as server:
                try:
                    server.starttls()
                except Exception:
                    pass
                if cfg.get("user") and cfg.get("password"):
                    server.login(cfg["user"], cfg["password"])
                server.sendmail(cfg["from_email"], send_to, msg.as_string())
        _save_sent_copy(msg.as_string())
        return True, ""
    except Exception as exc:
        logger.exception("SMTP send failed for %s", to_email)
        return False, str(exc)


def _save_sent_copy(message_text):
    """Append a copy to the mailbox Sent folder for StackMail/webmail history."""
    if os.environ.get("EMAIL_SAVE_SENT_COPY", "1") != "1":
        return
    host = os.environ.get("IMAP_HOST", "imap.stackmail.com").strip()
    port = int(os.environ.get("IMAP_PORT", "993") or 993)
    user = os.environ.get("SMTP_USER", "").strip()
    password = os.environ.get("SMTP_PASSWORD", "")
    if not host or not user or not password:
        return
    try:
        import imaplib
        import time
        with imaplib.IMAP4_SSL(host, port, timeout=SMTP_TIMEOUT_SECONDS) as imap:
            imap.login(user, password)
            for folder in ("Sent", "Sent Items", "INBOX.Sent"):
                status, _data = imap.append(folder, "", imaplib.Time2Internaldate(time.time()), message_text.encode("utf-8"))
                if status == "OK":
                    break
            imap.logout()
    except Exception as exc:
        logger.warning("Email sent, but could not save copy to Sent folder: %s", exc)


# ────────────────────────────────────────────────
# Comprehensive status email sender
# ────────────────────────────────────────────────
def send_status_email(registration_id, status, reason="", *,
                      override_fields=None, force=True, sent_by="system",
                      old_status=None):
    """Send a personalised status email with updated PDF attachment.

    Parameters
    ----------
    registration_id : int
    status : str  — payment status key (e.g. 'under_verification', 'paid')
    reason : str  — admin reason for rejection / cancellation
    override_fields : dict | None  — qualifier venue/date/time overrides
    force : bool  — bypass duplicate-email guard
    sent_by : str  — admin username or 'system'
    old_status : str | None  — previous status (if known, avoids stale DB read)

    Returns
    -------
    dict  — {ok, message, emails_sent, email_type}
    """
    from nexora.services.registrations import registration_details
    from nexora.services.pdf_tickets import build_ticket_pdf
    from nexora.services.tickets import ticket_member_roster

    details = registration_details(registration_id)
    if not details:
        return {"ok": False, "message": "Registration not found.", "emails_sent": 0, "email_type": ""}

    settings_row = query("SELECT * FROM settings WHERE id = 1", one=True)
    settings_dict = dict(settings_row) if settings_row else {}
    event_title = settings_dict.get("event_title", "Nexora Esports Championship")

    s = (status or "").lower().replace(" ", "_")
    if old_status is not None:
        old_status_raw = old_status.lower().replace(" ", "_") if old_status else ""
    else:
        old_status_raw = ""
        reg_row = query("SELECT payment_status FROM registrations WHERE id = ?", (registration_id,), one=True)
        if reg_row:
            old_status_raw = (reg_row["payment_status"] or "").lower().replace(" ", "_")

    # Determine email type
    if old_status_raw == "" or old_status_raw == s:
        email_type = "initial"
    else:
        email_type = "status_change"

    # Idempotency: skip if same status and not forced
    if not force and email_type == "status_change" and old_status_raw == s:
        return {"ok": True, "message": "No status change; email skipped.", "emails_sent": 0, "email_type": ""}

    # Build idempotency key
    idem_key = f"{registration_id}:{old_status_raw}:{s}:{email_type}"

    # Check for duplicate send
    if not force:
        existing = query(
            "SELECT id FROM email_logs WHERE idempotency_key = ? AND status = 'sent'",
            (idem_key,), one=True,
        )
        if existing:
            return {"ok": True, "message": "Email already sent for this status change.", "emails_sent": 0, "email_type": email_type}

    # Build email HTML
    html_body = build_status_email_html(details, s, event_title=event_title, reason=reason)

    # Generate updated PDF
    ticket_pdf_bytes = build_ticket_pdf(details, settings_dict)
    ticket_number = details.get("ticket_number", f"NX-{registration_id:04d}")

    subject = status_email_subject(s)

    # Collect recipients: leader + group members
    is_group = (details.get("entry_type") or "").lower() == "group"
    roster = ticket_member_roster(details) if is_group else []

    emails_sent = 0
    last_err = ""

    # 1) Leader email
    leader_email = (details.get("email") or "").strip()
    if leader_email:
        ok, err = _send_smtp_email(
            leader_email, subject, html_body,
            [(f"{ticket_number}.pdf", ticket_pdf_bytes)],
        )
        _log_email(registration_id, leader_email, subject, s, old_status_raw,
                    email_type, ok, err, ticket_pdf_bytes, idem_key, sent_by)
        if ok:
            emails_sent += 1
        else:
            last_err = err

    # 2) Group members — separate email each
    if is_group and roster:
        for member in roster:
            if member.get("number", 0) == 1:
                continue
            member_email = (member.get("email") or "").strip()
            if not member_email:
                continue
            member_name = member.get("name") or f"Member {member.get('number', '')}"
            member_html = build_status_email_html(
                details, s, recipient_name=member_name,
                event_title=event_title, reason=reason,
            )
            m_ok, m_err = _send_smtp_email(
                member_email, subject, member_html,
                [(f"{ticket_number}.pdf", ticket_pdf_bytes)],
            )
            member_idem = f"{registration_id}:{old_status_raw}:{s}:{email_type}:m{member.get('number', '')}"
            _log_email(registration_id, member_email, subject, s, old_status_raw,
                        email_type, m_ok, m_err, ticket_pdf_bytes, member_idem, sent_by)
            if m_ok:
                emails_sent += 1
            else:
                last_err = m_err

    # Update registration tracking columns
    execute(
        "UPDATE registrations SET last_email_status = ?, last_email_sent_at = datetime('now') WHERE id = ?",
        (s, registration_id),
    )

    if emails_sent > 0:
        return {"ok": True, "message": f"{emails_sent} email(s) sent.", "emails_sent": emails_sent, "email_type": email_type}
    return {"ok": False, "message": f"Email failed: {last_err}" if last_err else "No recipients.", "emails_sent": 0, "email_type": email_type}


def _log_email(registration_id, recipient_email, subject, new_status, previous_status,
               email_type, ok, error_message, pdf_bytes, idem_key, sent_by):
    """Write a row to email_logs."""
    pdf_attached = "1" if (ok and pdf_bytes) else "0"
    execute(
        """INSERT INTO email_logs
           (registration_id, recipient_email, subject, status, error_message,
            sent_by, created_at, email_type, previous_status, new_status,
            pdf_attached, retry_count, idempotency_key)
           VALUES (?, ?, ?, ?, ?, ?, datetime('now'), ?, ?, ?, ?, 0, ?)""",
        (registration_id, recipient_email, subject,
         "sent" if ok else "failed", error_message,
         sent_by, email_type, previous_status, new_status,
         pdf_attached, idem_key),
    )


def resend_status_email(log_id):
    """Retry a failed email by its email_logs id. Returns result dict."""
    row = query("SELECT * FROM email_logs WHERE id = ?", (log_id,), one=True)
    if not row:
        return {"ok": False, "message": "Email log not found."}
    if row["status"] == "sent" and not row.get("retry_count"):
        return {"ok": True, "message": "Email already sent successfully."}

    registration_id = row["registration_id"]
    new_status = row["new_status"] or row["status"]
    previous_status = row["previous_status"] or ""

    # Increment retry count
    execute(
        "UPDATE email_logs SET retry_count = retry_count + 1 WHERE id = ?",
        (log_id,),
    )

    return send_status_email(
        registration_id, new_status,
        force=True, sent_by="resend",
    )


# ────────────────────────────────────────────────
# Background queue enqueue functions
# ────────────────────────────────────────────────
def enqueue_status_email(conn, registration_id, status, reason="", sent_by="system", priority=5, old_status=None):
    """Send status email now and return the real SMTP result.

    cPanel/Passenger can freeze or kill background threads between requests.
    Synchronous delivery keeps registration, manual resend, and status-change
    actions honest: success means SMTP accepted the message, failure is logged.
    """
    try:
        return send_status_email(
            registration_id, status,
            reason=reason, force=True, sent_by=sent_by, old_status=old_status,
        )
    except Exception as exc:
        logger.exception("Status email send failed for registration %s", registration_id)
        return {"ok": False, "message": str(exc), "emails_sent": 0, "email_type": "status_change"}

def enqueue_initial_registration_email(conn, registration_id, status,
                                       sent_by="system"):
    """Enqueue the initial registration confirmation email."""
    return enqueue_status_email(
        conn, registration_id, status,
        reason="", sent_by=sent_by, priority=1,
    )
