"""Resolve per-verb NotificationTemplate overrides into rendered email parts.

When a row exists in NotificationTemplate for a notification's verb and is
active, the subject / body_text / body_html fields are rendered with the
Django template engine using a context that merges the caller-supplied
``email_context`` with the ``Notification`` instance and recipient.

The resolver is intentionally tolerant: a missing template, a missing
DB row, or a template-render error all fall back silently to the default
path. The point is to make admin-edited copy take effect when present, not
to block delivery on bad config.
"""

from __future__ import annotations

import logging
from typing import Any

from django.template import Context, Template, TemplateSyntaxError

logger = logging.getLogger(__name__)


def resolve_template(verb: str, *, notification, email_context: dict | None) -> dict[str, Any] | None:
    """Look up a NotificationTemplate row and render it.

    Returns a dict with any of ``subject``, ``body``, ``body_html``,
    ``headline``, ``action_label`` keys that the row provided. Returns
    ``None`` when no active template exists for the verb.
    """
    # Late import to avoid circular import on app startup.
    from apps.core.notifications.models import NotificationTemplate

    try:
        template = NotificationTemplate.objects.filter(verb=verb, is_active=True).first()
    except Exception:
        # DB not migrated yet (test bootstrap) — fall back silently.
        logger.debug("NotificationTemplate lookup failed", exc_info=True)
        return None

    if not template:
        return None

    base_ctx = dict(email_context or {})
    base_ctx.setdefault("notification", notification)
    base_ctx.setdefault("recipient", notification.recipient)
    base_ctx.setdefault(
        "recipient_name",
        notification.recipient.get_full_name()
        or (notification.recipient.email.split("@")[0] if notification.recipient.email else ""),
    )
    base_ctx.setdefault("message", notification.message)

    rendered: dict[str, Any] = {}
    try:
        rendered["subject"] = _render(template.subject, base_ctx)
    except TemplateSyntaxError:
        logger.exception("notification_template subject render failed verb=%s", verb)
        return None

    if template.body_text:
        try:
            rendered["body"] = _render(template.body_text, base_ctx)
        except TemplateSyntaxError:
            logger.exception("notification_template body_text render failed verb=%s", verb)

    if template.body_html:
        try:
            rendered["body_html"] = _render(template.body_html, base_ctx)
        except TemplateSyntaxError:
            logger.exception("notification_template body_html render failed verb=%s", verb)

    if template.headline_default and not base_ctx.get("headline"):
        rendered["headline"] = template.headline_default

    if template.action_label_default and not base_ctx.get("action_label"):
        rendered["action_label"] = template.action_label_default

    return rendered


def _render(template_str: str, ctx: dict[str, Any]) -> str:
    return Template(template_str).render(Context(ctx))
