from datetime import UTC, datetime

import pytest

from relay.server.models import Group, Message, Peer


class TestPeer:
    def test_requires_fields(self):
        peer = Peer(user_id="u-1", display_name="Alice", group_id="g1")
        assert peer.user_id == "u-1"
        assert peer.display_name == "Alice"
        assert peer.group_id == "g1"

    def test_defaults(self):
        peer = Peer(user_id="u-1", display_name="Alice", group_id="g1")
        assert peer.last_read_index == 0
        assert peer.online is False

    def test_explicit_fields(self):
        peer = Peer(
            user_id="u-42",
            display_name="Bob",
            group_id="team1",
            last_read_index=10,
            online=True,
        )
        assert peer.user_id == "u-42"
        assert peer.display_name == "Bob"
        assert peer.group_id == "team1"
        assert peer.last_read_index == 10
        assert peer.online is True

    def test_model_is_mutable(self):
        peer = Peer(user_id="u-1", display_name="Alice", group_id="g1")
        peer.online = True
        assert peer.online is True
        peer.last_read_index = 5
        assert peer.last_read_index == 5


class TestMessage:
    def test_auto_generates_message_id(self):
        msg = Message(
            from_peer="p1", from_display="host:proj", content="hello", group_id="g1"
        )
        assert len(msg.message_id) == 32
        assert msg.message_id.isalnum()

    def test_auto_generates_timestamp(self):
        before = datetime.now(UTC)
        msg = Message(
            from_peer="p1", from_display="host:proj", content="hello", group_id="g1"
        )
        after = datetime.now(UTC)
        assert before <= msg.timestamp <= after

    def test_model_is_frozen(self):
        msg = Message(
            from_peer="p1", from_display="host:proj", content="hello", group_id="g1"
        )
        with pytest.raises(Exception):
            msg.content = "changed"

    def test_unique_message_ids(self):
        msgs = [
            Message(from_peer="p1", from_display="d", content="hi", group_id="g1")
            for _ in range(50)
        ]
        ids = {m.message_id for m in msgs}
        assert len(ids) == 50


class TestGroup:
    def test_empty_group(self):
        group = Group(group_id="g1")
        assert group.group_id == "g1"
        assert group.peers == {}
        assert group.messages == []

    def test_add_peer_to_group(self):
        group = Group(group_id="g1")
        peer = Peer(user_id="u-1", display_name="Alice", group_id="g1")
        group.peers[peer.user_id] = peer
        assert peer.user_id in group.peers

    def test_add_message_to_group(self):
        group = Group(group_id="g1")
        msg = Message(
            from_peer="p1", from_display="host:proj", content="hello", group_id="g1"
        )
        group.messages.append(msg)
        assert len(group.messages) == 1
        assert group.messages[0].content == "hello"
