"""@mailman-authored "Acceptances & rejections" invite log — Phase A of
[[my-sea-invite-voice-blueprint]].

`log_sea_invite(sea_invite)` appends one interactive Line + spawns one Brief
on the invitee's single MAIL_ACCEPTANCE Post when an owner invites a bud to
their my-sea table. Models on `apps.billboard.tax.log_tax_debit` (the @taxman
ledger); the one genuinely new wrinkle is that the Line is *stateful* — its
OK/BYE buttons render from the linked `SeaInvite.status` (see post.html, A5),
so the single line transforms in place rather than appending accept/decline
lines.

Unlike the tax ledger, the prose carries no timestamp prefix (one invite =
one line; the A6 view dedups duplicate PENDING/ACCEPTED invites before
calling here, so the `Line.unique_together = (post, text)` invariant isn't
stressed by repeat identical prose). `Line.display_text` therefore needs no
MAIL_ACCEPTANCE branch.

The post_save guard in `billboard.models` nukes any Line on a MAIL_ACCEPTANCE
Post lacking admin_solicited=True, so this helper sets it True.
"""

from apps.billboard.models import (
    Brief,
    Line,
    MAIL_ACCEPTANCE_POST_TITLE,
    Post,
)
from apps.lyric.models import get_or_create_mailman, resolve_pronouns
from apps.lyric.templatetags.lyric_extras import at_handle


# Invite prose shown to the invitee. `{handle}` is wrapped in an
# `<a class="post-attribution">` whose href routes to the owner's per-bud
# landing page — bud landing page sprint 2026-05-27 replaced the in-Line
# OK/BYE form-button block w. this navigational anchor. post.html's
# `safe`-filter branch is gated on `line.author.username == 'mailman'`
# (alongside 'adman'/'taxman') so the anchor renders as HTML.
#
# `{poss}` = the owner's possessive pronoun ("their"/"his"/"her"/…), so the
# table reads as the owner's. Em dash matches the @taxman "Look!—" house style.
INVITE_TEMPLATE = (
    'Listen!—<a class="post-attribution" href="/billboard/buds/{owner_id}/">{handle}</a>'
    " invites you to {poss} drawing table. "
    "This invite will expire 24h from the time it was extended."
)


def log_sea_invite(sea_invite):
    """Append a Line to the invitee's "Acceptances & rejections" Post (creating
    the Post on first invite) + spawn a Brief that the invitee's next page-load
    surfaces as a slide-down banner. Links the new Line back onto the SeaInvite
    so its OK/BYE buttons render from `sea_invite.status`.

    Returns ``(post, line, brief)``. For an unregistered invitee (``invitee``
    FK still None) there is no per-user log surface yet — returns
    ``(None, None, None)`` (linking on registration is deferred, mirroring the
    long-standing RoomInvite-on-registration gap)."""
    invitee = sea_invite.invitee
    if invitee is None:
        return None, None, None

    owner = sea_invite.owner

    post, _ = Post.objects.get_or_create(
        owner=invitee,
        kind=Post.KIND_MAIL_ACCEPTANCE,
        defaults={"title": MAIL_ACCEPTANCE_POST_TITLE},
    )
    # Heal a title-less pre-feature Post once on next invite (mirrors the
    # tax-ledger / Note.grant_if_new title heal).
    if post.title != MAIL_ACCEPTANCE_POST_TITLE:
        post.title = MAIL_ACCEPTANCE_POST_TITLE
        post.save(update_fields=["title"])

    text = INVITE_TEMPLATE.format(
        owner_id=owner.id,
        handle=at_handle(owner),
        poss=resolve_pronouns(owner.pronouns)[2],
    )

    line = Line.objects.create(
        post=post,
        text=text,
        author=get_or_create_mailman(),
        admin_solicited=True,
    )
    # Link the Line onto the invite so post.html resolves OK/BYE state via the
    # `line.sea_invite` OneToOne reverse accessor.
    sea_invite.line = line
    sea_invite.save(update_fields=["line"])

    brief = Brief.objects.create(
        owner=invitee,
        post=post,
        line=line,
        kind=Brief.KIND_MAIL_ACCEPTANCE,
        title=MAIL_ACCEPTANCE_POST_TITLE,
    )
    return post, line, brief
