"""
Tests for Phase 26: Social Media for AI Agents.
"""

import json
import pytest


@pytest.fixture(autouse=True)
def _isolate(tmp_path, monkeypatch):
    social = tmp_path / "social"
    posts = social / "posts"
    follows = social / "follows"
    reactions = social / "reactions"
    for d in (social, posts, follows, reactions):
        d.mkdir(parents=True, exist_ok=True)

    import brynq.server as srv
    monkeypatch.setattr(srv, "BROKER_DIR", tmp_path)

    import brynq.social as s
    monkeypatch.setattr(s, "SOCIAL_DIR", social)
    monkeypatch.setattr(s, "POSTS_DIR", posts)
    monkeypatch.setattr(s, "FOLLOWS_DIR", follows)
    monkeypatch.setattr(s, "REACTIONS_DIR", reactions)
    monkeypatch.setattr(s, "TRENDING_FILE", social / "trending.json")


class TestPosts:
    def test_create_post(self):
        from brynq.social import create_post
        p = create_post("Hello swarm!", author_id="a1", author_name="Agent1")
        assert p["post_id"]
        assert p["content"] == "Hello swarm!"
        assert p["post_type"] == "status"

    def test_create_showcase(self):
        from brynq.social import create_post
        p = create_post("Built the federation module", post_type="showcase",
                        tags=["federation"], project="brynq", pinned=True)
        assert p["post_type"] == "showcase"
        assert p["pinned"] is True
        assert "federation" in p["tags"]

    def test_create_empty(self):
        from brynq.social import create_post
        r = create_post("")
        assert "error" in r

    def test_create_too_long(self):
        from brynq.social import create_post
        r = create_post("x" * 2001)
        assert "error" in r

    def test_invalid_type(self):
        from brynq.social import create_post
        r = create_post("hello", post_type="tweet")
        assert "error" in r

    def test_get_post(self):
        from brynq.social import create_post, get_post
        p = create_post("Test", author_id="a1")
        result = get_post(p["post_id"])
        assert result["content"] == "Test"

    def test_get_nonexistent(self):
        from brynq.social import get_post
        assert get_post("nope") is None

    def test_delete_post(self):
        from brynq.social import create_post, delete_post, get_post
        p = create_post("Delete me", author_id="a1")
        result = delete_post(p["post_id"], requester_id="a1")
        assert "deleted" in result
        assert get_post(p["post_id"]) is None

    def test_delete_wrong_author(self):
        from brynq.social import create_post, delete_post
        p = create_post("Mine", author_id="a1")
        result = delete_post(p["post_id"], requester_id="a2")
        assert "error" in result

    def test_list_posts(self):
        from brynq.social import create_post, list_posts
        create_post("Post 1", author_id="a1")
        create_post("Post 2", author_id="a2")
        posts = list_posts()
        assert len(posts) == 2

    def test_list_by_author(self):
        from brynq.social import create_post, list_posts
        create_post("By A", author_id="a1")
        create_post("By B", author_id="a2")
        posts = list_posts(author_id="a1")
        assert len(posts) == 1

    def test_list_by_tag(self):
        from brynq.social import create_post, list_posts
        create_post("Tagged", tags=["python"], author_id="a1")
        create_post("Not tagged", author_id="a1")
        posts = list_posts(tag="python")
        assert len(posts) == 1

    def test_reply(self):
        from brynq.social import create_post, reply_to_post, get_post
        p = create_post("Original", author_id="a1")
        reply = reply_to_post(p["post_id"], "Great post!", author_id="a2")
        assert reply["reply_to"] == p["post_id"]
        parent = get_post(p["post_id"])
        assert parent["reply_count"] == 1

    def test_reply_nonexistent(self):
        from brynq.social import reply_to_post
        result = reply_to_post("nope", "reply")
        assert "error" in result


class TestFollows:
    def test_follow(self):
        from brynq.social import follow
        result = follow("target-1", follower_id="me")
        assert result["followed"] == "target-1"

    def test_follow_self(self):
        from brynq.social import follow
        result = follow("me", follower_id="me")
        assert "error" in result

    def test_follow_duplicate(self):
        from brynq.social import follow
        follow("t1", follower_id="f1")
        result = follow("t1", follower_id="f1")
        assert result.get("already_following") is True

    def test_unfollow(self):
        from brynq.social import follow, unfollow, get_following
        follow("t2", follower_id="f2")
        unfollow("t2", follower_id="f2")
        assert "t2" not in get_following("f2")

    def test_unfollow_not_following(self):
        from brynq.social import unfollow
        result = unfollow("nobody", follower_id="me")
        assert "error" in result

    def test_get_following(self):
        from brynq.social import follow, get_following
        follow("a", follower_id="me")
        follow("b", follower_id="me")
        following = get_following("me")
        assert set(following) == {"a", "b"}

    def test_get_followers(self):
        from brynq.social import follow, get_followers
        follow("star", follower_id="fan1")
        follow("star", follower_id="fan2")
        followers = get_followers("star")
        assert set(followers) == {"fan1", "fan2"}


class TestReactions:
    def test_react(self):
        from brynq.social import create_post, react_to_post, get_post
        p = create_post("React to me", author_id="a1")
        result = react_to_post(p["post_id"], "star", reactor_id="a2")
        assert result["new_count"] == 1
        updated = get_post(p["post_id"])
        assert updated["reaction_counts"]["star"] == 1

    def test_invalid_reaction(self):
        from brynq.social import create_post, react_to_post
        p = create_post("Post", author_id="a1")
        result = react_to_post(p["post_id"], "love")
        assert "error" in result

    def test_react_nonexistent(self):
        from brynq.social import react_to_post
        result = react_to_post("nope", "star")
        assert "error" in result

    def test_get_reactions(self):
        from brynq.social import create_post, react_to_post, get_reactions
        p = create_post("Popular", author_id="a1")
        react_to_post(p["post_id"], "star", reactor_id="a2")
        react_to_post(p["post_id"], "boost", reactor_id="a3")
        reactions = get_reactions(p["post_id"])
        assert len(reactions) == 2

    def test_get_reactions_empty(self):
        from brynq.social import get_reactions
        assert get_reactions("nope") == []


class TestFeed:
    def test_feed(self):
        from brynq.social import create_post, follow, get_feed
        create_post("Post by A", author_id="a1")
        create_post("Post by B", author_id="a2")
        create_post("Post by C", author_id="a3")
        follow("a1", follower_id="me")
        follow("a2", follower_id="me")
        feed = get_feed("me")
        assert len(feed) == 2
        authors = {p["author_id"] for p in feed}
        assert authors == {"a1", "a2"}

    def test_feed_empty(self):
        from brynq.social import get_feed
        assert get_feed("loner") == []


class TestTrending:
    def test_compute_trending(self):
        from brynq.social import create_post, react_to_post, compute_trending
        p1 = create_post("Viral post", author_id="a1")
        react_to_post(p1["post_id"], "star", reactor_id="a2")
        react_to_post(p1["post_id"], "boost", reactor_id="a3")
        create_post("Quiet post", author_id="a2")
        result = compute_trending(hours=24, limit=5)
        assert len(result["trending_posts"]) >= 1
        assert result["trending_posts"][0]["post_id"] == p1["post_id"]

    def test_get_trending_empty(self):
        from brynq.social import get_trending
        result = get_trending()
        assert result["trending_posts"] == []


class TestProfileSocial:
    def test_profile_posts(self):
        from brynq.social import create_post, get_profile_posts
        create_post("Regular", author_id="a1")
        create_post("Showcase", author_id="a1", pinned=True)
        all_posts = get_profile_posts("a1")
        assert len(all_posts) == 2
        pinned = get_profile_posts("a1", pinned_only=True)
        assert len(pinned) == 1

    def test_social_stats(self):
        from brynq.social import create_post, follow, react_to_post, get_social_stats
        p = create_post("Post", author_id="popular")
        react_to_post(p["post_id"], "star", reactor_id="fan1")
        follow("popular", follower_id="fan1")
        follow("popular", follower_id="fan2")
        stats = get_social_stats("popular")
        assert stats["total_posts"] == 1
        assert stats["total_followers"] == 2
        assert stats["total_reactions_received"] == 1
