"""ITs for post.html invitee-vs-owner header rendering.

The "just me, @owner the {title}" / "shared between … & me, @owner …" lines
were owner-centric (the legacy phrasing assumed the viewer is the post
creator). For an invitee (a user in post.shared_with), that prose is
confusing. This view branches the .post-header block:

  • Owner viewing → unchanged existing prose.
  • Invitee viewing (sole)  → "shared with me, @viewer the {title}" +
                              "created by @owner the {owner_title}".
  • Invitee viewing (multi) → "shared with {other_recipients ...}" +
                              "& me, @viewer the {title}" +
                              "created by @owner the {owner_title}".

The view layer adds `viewer_is_owner` + `other_recipients` to the
context; template branches on those.
"""
from django.test import TestCase
from django.urls import reverse

from apps.billboard.models import Line, Post
from apps.lyric.models import User


class PostInviteeViewContextTest(TestCase):
    """Context vars: viewer_is_owner + other_recipients."""

    def setUp(self):
        self.owner = User.objects.create(email="owner@test.io", username="owner")
        self.alice = User.objects.create(email="alice@test.io", username="alice")
        self.bob   = User.objects.create(email="bob@test.io",   username="bob")
        self.post = Post.objects.create(owner=self.owner, title="Coolio")
        Line.objects.create(post=self.post, text="seed", author=self.owner)

    def test_owner_viewing_sets_viewer_is_owner_true(self):
        self.client.force_login(self.owner)
        response = self.client.get(reverse("billboard:view_post", args=[self.post.id]))
        self.assertTrue(response.context["viewer_is_owner"])

    def test_invitee_viewing_sets_viewer_is_owner_false(self):
        self.post.shared_with.add(self.alice)
        self.client.force_login(self.alice)
        response = self.client.get(reverse("billboard:view_post", args=[self.post.id]))
        self.assertFalse(response.context["viewer_is_owner"])

    def test_other_recipients_excludes_viewer(self):
        """For an invitee, other_recipients = shared_with minus self."""
        self.post.shared_with.add(self.alice, self.bob)
        self.client.force_login(self.alice)
        response = self.client.get(reverse("billboard:view_post", args=[self.post.id]))
        others = list(response.context["other_recipients"])
        self.assertIn(self.bob, others)
        self.assertNotIn(self.alice, others)

    def test_other_recipients_empty_for_sole_invitee(self):
        self.post.shared_with.add(self.alice)
        self.client.force_login(self.alice)
        response = self.client.get(reverse("billboard:view_post", args=[self.post.id]))
        self.assertEqual(list(response.context["other_recipients"]), [])

    def test_other_recipients_for_owner_is_full_shared_with(self):
        """Owner viewing: other_recipients includes everyone (no self exclusion)."""
        self.post.shared_with.add(self.alice, self.bob)
        self.client.force_login(self.owner)
        response = self.client.get(reverse("billboard:view_post", args=[self.post.id]))
        others = list(response.context["other_recipients"])
        self.assertIn(self.alice, others)
        self.assertIn(self.bob, others)


class PostInviteeViewTemplateTest(TestCase):
    """Template prose: invitee branch shows "shared with me, …" /
    "created by @owner …" — does NOT show the owner-centric "just me" or
    "shared between"."""

    def setUp(self):
        self.owner = User.objects.create(email="owner@test.io", username="owner")
        self.alice = User.objects.create(email="alice@test.io", username="alice")
        self.bob   = User.objects.create(email="bob@test.io",   username="bob")
        self.post = Post.objects.create(owner=self.owner, title="Coolio")
        Line.objects.create(post=self.post, text="seed", author=self.owner)

    def test_sole_invitee_sees_shared_with_me(self):
        self.post.shared_with.add(self.alice)
        self.client.force_login(self.alice)
        response = self.client.get(reverse("billboard:view_post", args=[self.post.id]))
        body = response.content.decode()
        self.assertIn("shared with me", body)
        self.assertIn("@alice", body)

    def test_sole_invitee_does_not_see_just_me_or_shared_between(self):
        """Scope to .post-header — the bud-panel JS includes 'just me,' as
        a regex literal in inline script, so a body-wide string match
        false-positives."""
        import lxml.html
        self.post.shared_with.add(self.alice)
        self.client.force_login(self.alice)
        body = self.client.get(reverse("billboard:view_post", args=[self.post.id])).content.decode()
        tree = lxml.html.fromstring(body)
        header_text = tree.cssselect(".post-header")[0].text_content()
        self.assertNotIn("just me,", header_text)
        self.assertNotIn("shared between", header_text)

    def test_invitee_sees_created_by_owner(self):
        self.post.shared_with.add(self.alice)
        self.client.force_login(self.alice)
        body = self.client.get(reverse("billboard:view_post", args=[self.post.id])).content.decode()
        self.assertIn("created by", body)
        self.assertIn("@owner", body)

    def test_multi_invitee_sees_shared_with_others_then_amp_me(self):
        self.post.shared_with.add(self.alice, self.bob)
        self.client.force_login(self.alice)
        body = self.client.get(reverse("billboard:view_post", args=[self.post.id])).content.decode()
        self.assertIn("shared with", body)
        self.assertIn("@bob", body)
        self.assertIn("&amp; me", body)
        self.assertIn("@alice", body)

    def test_multi_invitee_does_not_see_self_in_recipients_line(self):
        """The recipients line lists OTHER invitees, not self."""
        self.post.shared_with.add(self.alice, self.bob)
        self.client.force_login(self.alice)
        body = self.client.get(reverse("billboard:view_post", args=[self.post.id])).content.decode()
        # Coarse check: "shared with @bob" appears w/o @alice in same line
        # (since alice's "@alice" is on the "& me" line below). The full
        # body contains both, but the .post-shared-recipients line should
        # only list other_recipients (i.e., bob, not alice).
        # Use a narrower lxml-style assertion.
        import lxml.html
        tree = lxml.html.fromstring(body)
        recipients_p = tree.cssselect(".post-shared-recipients")
        self.assertEqual(len(recipients_p), 1)
        rec_text = recipients_p[0].text_content()
        self.assertIn("@bob", rec_text)
        self.assertNotIn("@alice", rec_text)

    def test_owner_view_unchanged_when_recipients_present(self):
        """Owner sees 'shared between' (old behavior)."""
        self.post.shared_with.add(self.alice)
        self.client.force_login(self.owner)
        body = self.client.get(reverse("billboard:view_post", args=[self.post.id])).content.decode()
        self.assertIn("shared between", body)
        self.assertIn("&amp; me", body)
        self.assertNotIn("created by", body)

    def test_owner_view_just_me_when_no_recipients(self):
        """Owner with no recipients: 'just me, …' (old behavior)."""
        self.client.force_login(self.owner)
        body = self.client.get(reverse("billboard:view_post", args=[self.post.id])).content.decode()
        self.assertIn("just me,", body)
        self.assertNotIn("created by", body)
