"""
Tests for Phase 28: Platform Analytics.
"""

import json
import pytest


@pytest.fixture(autouse=True)
def _isolate(tmp_path, monkeypatch):
    channels = tmp_path / "channels"
    sessions = tmp_path / "sessions"
    analytics = tmp_path / "analytics"
    snapshots = analytics / "snapshots"
    for d in (channels, sessions, analytics, snapshots):
        d.mkdir(parents=True, exist_ok=True)

    import brynq.server as srv
    monkeypatch.setattr(srv, "BROKER_DIR", tmp_path)
    monkeypatch.setattr(srv, "CHANNELS_DIR", channels)
    monkeypatch.setattr(srv, "SESSIONS_DIR", sessions)

    import brynq.platform_analytics as pa
    monkeypatch.setattr(pa, "ANALYTICS_DIR", analytics)
    monkeypatch.setattr(pa, "SNAPSHOTS_DIR", snapshots)
    monkeypatch.setattr(pa, "METRICS_FILE", analytics / "metrics.json")
    monkeypatch.setattr(pa, "BROKER_DIR", tmp_path)
    monkeypatch.setattr(pa, "CHANNELS_DIR", channels)
    monkeypatch.setattr(pa, "SESSIONS_DIR", sessions)


def _create_session(tmp_path, sid, platform="claude"):
    sessions = tmp_path / "sessions"
    sessions.mkdir(parents=True, exist_ok=True)
    data = {"session_id": sid, "platform": platform}
    (sessions / f"{sid}.json").write_text(json.dumps(data))


def _create_channel(tmp_path, name, messages=5):
    channels = tmp_path / "channels"
    channels.mkdir(parents=True, exist_ok=True)
    with open(channels / f"{name}.jsonl", "w") as f:
        for i in range(messages):
            f.write(json.dumps({"id": str(i), "message": f"msg {i}"}) + "\n")


class TestAgentMetrics:
    def test_empty(self):
        from brynq.platform_analytics import collect_agent_metrics
        m = collect_agent_metrics()
        assert m["total"] == 0

    def test_with_sessions(self, tmp_path):
        _create_session(tmp_path, "a1", "claude")
        _create_session(tmp_path, "a2", "gemini")
        from brynq.platform_analytics import collect_agent_metrics
        m = collect_agent_metrics()
        assert m["total"] == 2
        assert m["by_platform"]["claude"] == 1
        assert m["by_platform"]["gemini"] == 1


class TestChannelMetrics:
    def test_empty(self):
        from brynq.platform_analytics import collect_channel_metrics
        m = collect_channel_metrics()
        assert m["total"] == 0

    def test_with_channels(self, tmp_path):
        _create_channel(tmp_path, "general", 10)
        _create_channel(tmp_path, "tasks", 5)
        from brynq.platform_analytics import collect_channel_metrics
        m = collect_channel_metrics()
        assert m["total"] == 2
        assert m["total_messages"] == 15


class TestTaskMetrics:
    def test_empty(self):
        from brynq.platform_analytics import collect_task_metrics
        m = collect_task_metrics()
        assert m["total"] == 0

    def test_with_tasks(self, tmp_path):
        tasks_dir = tmp_path / "tasks"
        tasks_dir.mkdir(exist_ok=True)
        for i, status in enumerate(["pending", "completed", "completed", "failed"]):
            (tasks_dir / f"task-{i}.json").write_text(
                json.dumps({"status": status, "priority": "normal"})
            )
        from brynq.platform_analytics import collect_task_metrics
        m = collect_task_metrics()
        assert m["total"] == 4
        assert m["by_status"]["completed"] == 2
        assert m["by_status"]["failed"] == 1


class TestProfileMetrics:
    def test_empty(self):
        from brynq.platform_analytics import collect_profile_metrics
        m = collect_profile_metrics()
        assert m["total"] == 0

    def test_with_profiles(self, tmp_path):
        profiles = tmp_path / "profiles"
        profiles.mkdir(exist_ok=True)
        (profiles / "p1.json").write_text(json.dumps({
            "reputation": 4.5, "skills": ["python", "testing"], "availability": "available",
        }))
        (profiles / "p2.json").write_text(json.dumps({
            "reputation": 3.5, "skills": ["python", "rust"], "availability": "busy",
        }))
        from brynq.platform_analytics import collect_profile_metrics
        m = collect_profile_metrics()
        assert m["total"] == 2
        assert m["avg_reputation"] == 4.0
        assert m["top_skills"]["python"] == 2


class TestCollectAll:
    def test_collect_all(self, tmp_path):
        _create_session(tmp_path, "s1")
        _create_channel(tmp_path, "general", 3)
        from brynq.platform_analytics import collect_all_metrics
        m = collect_all_metrics()
        assert "timestamp" in m
        assert "agents" in m
        assert "channels" in m
        assert "tasks" in m
        assert "health_score" in m
        assert m["health_score"] >= 0

    def test_get_latest(self, tmp_path):
        _create_session(tmp_path, "s1")
        from brynq.platform_analytics import collect_all_metrics, get_latest_metrics
        collect_all_metrics()
        latest = get_latest_metrics()
        assert latest is not None
        assert "timestamp" in latest

    def test_get_latest_none(self):
        from brynq.platform_analytics import get_latest_metrics
        assert get_latest_metrics() is None


class TestSnapshots:
    def test_take_snapshot(self, tmp_path):
        _create_session(tmp_path, "s1")
        from brynq.platform_analytics import take_snapshot
        result = take_snapshot()
        assert "snapshot_id" in result

    def test_list_snapshots(self, tmp_path):
        _create_session(tmp_path, "s1")
        from brynq.platform_analytics import take_snapshot, list_snapshots
        take_snapshot()
        snaps = list_snapshots()
        assert len(snaps) >= 1

    def test_get_snapshot(self, tmp_path):
        _create_session(tmp_path, "s1")
        from brynq.platform_analytics import take_snapshot, get_snapshot
        result = take_snapshot()
        snap = get_snapshot(result["snapshot_id"])
        assert snap is not None
        assert "agents" in snap

    def test_get_nonexistent(self):
        from brynq.platform_analytics import get_snapshot
        assert get_snapshot("nope") is None

    def test_compare_snapshots(self, tmp_path):
        from brynq.platform_analytics import take_snapshot, compare_snapshots
        s1 = take_snapshot()
        import time; time.sleep(0.01)
        s2 = take_snapshot()
        result = compare_snapshots(s1["snapshot_id"], s2["snapshot_id"])
        assert "deltas" in result
        assert "from" in result
        assert "to" in result

    def test_compare_missing(self):
        from brynq.platform_analytics import compare_snapshots
        result = compare_snapshots("a", "b")
        assert "error" in result
