"""ITs for share-post async-Brief flow (C3.b).

POST /billboard/post/<uuid>/share-post w. Accept: application/json now:
  - Adds the recipient to Post.shared_with (if registered, not the sharer)
  - Appends a Line to the Post recording the share event
  - Spawns a Brief(kind=SHARE_INVITE) for the sharer that JS slide-downs
  - Returns JSON {brief: {…}, line_text: "…"}; no redirect, no messages

Legacy form-submit (no Accept: application/json) still redirects + flashes
the privacy-safe success message — kept for non-AJAX fallback / older FTs.
"""

from django.test import TestCase
from django.urls import reverse

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


class SharePostAsyncTest(TestCase):
    def setUp(self):
        self.sharer = User.objects.create(email="sharer@test.io")
        self.client.force_login(self.sharer)
        self.post = Post.objects.create(owner=self.sharer)

    def _share_async(self, recipient_email):
        return self.client.post(
            reverse("billboard:share_post", args=[self.post.id]),
            data={"recipient": recipient_email},
            HTTP_ACCEPT="application/json",
        )

    def test_async_share_returns_brief_payload(self):
        User.objects.create(email="alice@test.io")
        response = self._share_async("alice@test.io")
        self.assertEqual(response.status_code, 200)
        body = response.json()
        self.assertIn("brief", body)
        self.assertIn("line_text", body)

    def test_async_share_appends_line_to_post(self):
        User.objects.create(email="alice@test.io")
        self.assertEqual(self.post.lines.count(), 0)
        self._share_async("alice@test.io")
        self.assertEqual(self.post.lines.count(), 1)
        line = self.post.lines.first()
        self.assertIn("alice@test.io", line.text)

    def test_async_share_creates_share_invite_brief_for_sharer(self):
        User.objects.create(email="alice@test.io")
        self._share_async("alice@test.io")
        brief = Brief.objects.get(owner=self.sharer)
        self.assertEqual(brief.kind, Brief.KIND_SHARE_INVITE)
        self.assertEqual(brief.post, self.post)
        self.assertIsNotNone(brief.line)
        self.assertTrue(brief.is_unread)

    def test_async_share_adds_registered_recipient_to_shared_with(self):
        alice = User.objects.create(email="alice@test.io")
        self._share_async("alice@test.io")
        self.assertIn(alice, self.post.shared_with.all())

    def test_async_share_unregistered_recipient_still_appends_line_and_brief(self):
        """Privacy: even if the email isn't registered, the sharer gets the
        same confirmation Brief + Line. Otherwise the response shape would
        leak whether an address is on the system."""
        response = self._share_async("ghost@test.io")
        self.assertEqual(response.status_code, 200)
        self.assertEqual(self.post.lines.count(), 1)
        self.assertEqual(Brief.objects.filter(owner=self.sharer).count(), 1)

    def test_async_share_does_not_add_owner_as_recipient(self):
        """Sharer shares w. their own email — no shared_with add, no Line, no
        Brief; response carries brief: null so the JS just no-ops."""
        response = self._share_async("sharer@test.io")
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json()["brief"], None)
        self.assertEqual(self.post.lines.count(), 0)
        self.assertEqual(Brief.objects.filter(owner=self.sharer).count(), 0)
        self.assertNotIn(self.sharer, self.post.shared_with.all())

    def test_async_share_brief_payload_carries_share_invite_kind(self):
        User.objects.create(email="alice@test.io")
        body = self._share_async("alice@test.io").json()
        self.assertEqual(body["brief"]["kind"], "share_invite")
        self.assertIn("alice@test.io", body["line_text"])

    def test_async_reshare_same_recipient_is_silent_noop(self):
        """Sharing the same recipient twice is a silent no-op — Post.shared_with
        M2M is idempotent so a second add is meaningless, and we don't want a
        duplicate Line cluttering the thread. Response is 200 with brief=null."""
        User.objects.create(email="alice@test.io")
        self._share_async("alice@test.io")
        self.assertEqual(self.post.lines.count(), 1)
        before_brief_count = Brief.objects.filter(owner=self.sharer).count()

        response = self._share_async("alice@test.io")

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json()["brief"], None)
        # No second Line, no second Brief.
        self.assertEqual(self.post.lines.count(), 1)
        self.assertEqual(
            Brief.objects.filter(owner=self.sharer).count(),
            before_brief_count,
        )

    def test_async_share_line_text_drops_timestamp(self):
        """The share Line's text is plain "Shared with X" — no "at <iso ts>"
        suffix (timestamp display lives on the per-Line `<time>` element now)."""
        User.objects.create(email="alice@test.io")
        self._share_async("alice@test.io")
        line = self.post.lines.first()
        self.assertEqual(line.text, "Shared with alice@test.io")
        self.assertNotIn(" at ", line.text)

    def test_async_share_line_author_is_sharer_not_adman(self):
        """User-created share Lines attribute to the sharer (the post owner
        doing the share), not the system adman entity."""
        User.objects.create(email="alice@test.io")
        self._share_async("alice@test.io")
        line = self.post.lines.first()
        self.assertEqual(line.author, self.sharer)


class SharePostLegacyRedirectTest(TestCase):
    """Legacy form-submit path (no Accept: application/json) is preserved —
    redirects + flashes the privacy-safe message + adds shared_with. Existing
    FTs that submit the share form via Selenium still work."""

    def setUp(self):
        self.sharer = User.objects.create(email="sharer@test.io")
        self.client.force_login(self.sharer)
        self.post = Post.objects.create(owner=self.sharer)

    def test_form_submit_still_redirects(self):
        User.objects.create(email="alice@test.io")
        response = self.client.post(
            reverse("billboard:share_post", args=[self.post.id]),
            data={"recipient": "alice@test.io"},
        )
        self.assertEqual(response.status_code, 302)
        self.assertEqual(response["Location"], reverse("billboard:view_post", args=[self.post.id]))

    def test_form_submit_still_adds_shared_with(self):
        alice = User.objects.create(email="alice@test.io")
        self.client.post(
            reverse("billboard:share_post", args=[self.post.id]),
            data={"recipient": "alice@test.io"},
        )
        self.assertIn(alice, self.post.shared_with.all())
