"""FT for the @mailman "Acceptances & rejections" Post + cross-page Brief
behaviour after the bud-landing-page sprint refactor.

Pre-sprint: the @mailman invite Line carried inline OK/BYE form buttons
+ an "Accepted <date>" badge (see apps/billboard/_partials/_invite_actions.html).
Post-sprint: that interaction surface migrates entirely onto bud.html —
the Line's prose becomes the interactive surface via an
`<a class="post-attribution">@<owner></a>` inside `span.post-line-text`
whose href routes to /billboard/buds/<owner_id>/. The bud.html page then
absorbs the accept/decline + spectator-link flow that used to live in the
Post.

Spec recap:
- When the bud has invited the user, a Brief slides down wherever the user
  is on the site; FYI links to the @mailman Acceptances & rejections Post.
- The Post's mailman Line contains an `a.post-attribution` around the
  inviter's handle, href=/billboard/buds/<inviter_id>/.
- The Line carries NO `.invite-actions` block (OK/BYE/Accepted/etc. removed).
- Following the post-attribution link auto-adds the inviter to the user's
  buds list if not already a bud (verified separately in
  test_bill_bud_page.py::BudPageAutoAddOnFirstVisitTest).
"""
from selenium.webdriver.common.by import By

from apps.billboard.mail import log_sea_invite
from apps.gameboard.models import SeaInvite
from apps.lyric.models import User, get_or_create_mailman


def _create_pending_invite(owner, invitee):
    """Reusable helper: alice → me PENDING SeaInvite + the @mailman Post +
    Line + Brief log entry. Mirrors what gameboard.invite-bud would create
    in real flow; calling log_sea_invite directly avoids dragging the
    bud-invite POST view into the FT setup."""
    inv = SeaInvite.objects.create(
        owner=owner,
        invitee_email=invitee.email,
        invitee=invitee,
        status=SeaInvite.PENDING,
    )
    log_sea_invite(inv)
    return inv


from .base import FunctionalTest


class MailmanPostStructureTest(FunctionalTest):
    def setUp(self):
        super().setUp()
        self.gamer = User.objects.create(email="me@test.io", username="me")
        self.alice = User.objects.create(email="alice@test.io", username="alice")
        get_or_create_mailman()
        _create_pending_invite(self.alice, self.gamer)
        self.create_pre_authenticated_session("me@test.io")

    def _navigate_to_mailman_post(self):
        """Land on the user's @mailman post directly via the my_posts list.
        Avoids hard-coding the post UUID."""
        from apps.billboard.models import Post
        post = Post.objects.get(owner=self.gamer, kind=Post.KIND_MAIL_ACCEPTANCE)
        self.browser.get(
            self.live_server_url + f"/billboard/post/{post.id}/"
        )

    def test_mailman_line_contains_post_attribution_anchor_to_bud_page(self):
        """span.post-line-text on the @mailman Line wraps the inviter's
        handle in an <a class="post-attribution"> whose href is the bud
        landing page for the inviter. Anchor text = the bud's at_handle
        (e.g. '@alice'); the surrounding prose stays in plain text."""
        self._navigate_to_mailman_post()
        line = self.wait_for(lambda: self.browser.find_element(
            By.CSS_SELECTOR, ".post-line--system"
        ))
        anchor = line.find_element(
            By.CSS_SELECTOR, "span.post-line-text a.post-attribution"
        )
        self.assertEqual(anchor.text, "@alice")
        href = anchor.get_attribute("href")
        self.assertIn(f"/billboard/buds/{self.alice.id}/", href)

    def test_mailman_line_no_longer_renders_ok_bye_or_accepted_badge(self):
        """The pre-sprint .invite-actions block is GONE — the entire
        accept/decline + accepted-date UX migrates onto bud.html. The Line
        carries prose only."""
        self._navigate_to_mailman_post()
        line = self.wait_for(lambda: self.browser.find_element(
            By.CSS_SELECTOR, ".post-line--system"
        ))
        self.assertEqual(
            line.find_elements(By.CSS_SELECTOR, ".invite-actions"),
            [],
        )
        self.assertEqual(
            line.find_elements(By.CSS_SELECTOR, ".invite-ok-btn"),
            [],
        )
        self.assertEqual(
            line.find_elements(By.CSS_SELECTOR, ".invite-bye-btn"),
            [],
        )
        self.assertEqual(
            line.find_elements(By.CSS_SELECTOR, ".invite-badge--accepted"),
            [],
        )

    def test_mailman_line_no_invite_actions_remain_after_invite_accepted(self):
        """Even if the SeaInvite is in ACCEPTED state, the Line stays prose-
        only — there's no longer an 'Accepted <date>' badge here (that
        information surfaces on bud.html instead). Asserts the .invite-
        actions sweep is unconditional, not just PENDING-only."""
        SeaInvite.objects.filter(invitee=self.gamer).update(status=SeaInvite.ACCEPTED)
        self._navigate_to_mailman_post()
        line = self.wait_for(lambda: self.browser.find_element(
            By.CSS_SELECTOR, ".post-line--system"
        ))
        self.assertEqual(
            line.find_elements(By.CSS_SELECTOR, ".invite-actions"),
            [],
        )


class MailmanBriefSurfacesOnAnyPageTest(FunctionalTest):
    """The Brief spawned by `log_sea_invite` should surface wherever the
    user lands next — not only on the Post itself. Existing Brief delivery
    is page-load based (banner injected by the server-rendered template +
    note.js Brief.showBanner). The FT verifies the cross-page surface by
    visiting an unrelated page first."""

    def setUp(self):
        super().setUp()
        self.gamer = User.objects.create(email="me@test.io", username="me")
        self.alice = User.objects.create(email="alice@test.io", username="alice")
        get_or_create_mailman()
        _create_pending_invite(self.alice, self.gamer)
        self.create_pre_authenticated_session("me@test.io")

    def test_brief_appears_on_unrelated_page_load(self):
        """Land on `/` (not the Post itself). The Brief banner should
        still be present — the invite spawned an unread Brief, which
        the next page-load surfaces sitewide via the `mail_brief_
        payload` context processor + base.html auto-showBanner."""
        self.browser.get(self.live_server_url + "/")
        banner = self.wait_for(lambda: self.browser.find_element(
            By.CSS_SELECTOR, ".note-banner"
        ))
        self.assertIn(
            "Acceptances & rejections",
            banner.find_element(By.CSS_SELECTOR, ".note-banner__title").text,
        )

    def test_brief_fyi_navigates_to_mailman_post(self):
        """FYI link on the slide-down banner is the cross-page nav into the
        Acceptances & rejections Post. Click → land on the Post page."""
        self.browser.get(self.live_server_url + "/")
        fyi = self.wait_for(lambda: self.browser.find_element(
            By.CSS_SELECTOR, ".note-banner__fyi"
        ))
        fyi.click()
        # Post URL pattern is /billboard/post/<uuid>/
        self.wait_for(lambda: self.assertIn(
            "/billboard/post/", self.browser.current_url
        ))
        # And the page is the user's @mailman post (title visible).
        self.wait_for(lambda: self.assertIn(
            "Acceptances & rejections",
            self.browser.find_element(By.CSS_SELECTOR, ".post-title").text,
        ))
