"""Tests for alive.network.discovery — peer discovery and registry."""

import time
import json
from unittest.mock import patch, MagicMock

import pytest


class TestPeerRegistry:
    def test_register_new_peer(self):
        from alive.network.discovery import PeerRegistry

        reg = PeerRegistry()
        announcement = {
            "agent": {"agent_id": "alp-123", "alias": "friend", "skill_count": 5},
            "port": 8585,
        }
        is_new = reg.register("192.168.1.10", announcement)
        assert is_new is True
        assert "alp-123" in reg.peers

    def test_register_existing_peer_returns_false(self):
        from alive.network.discovery import PeerRegistry

        reg = PeerRegistry()
        ann = {"agent": {"agent_id": "alp-123", "alias": "x"}, "port": 8585}
        reg.register("1.2.3.4", ann)
        is_new = reg.register("1.2.3.4", ann)
        assert is_new is False

    def test_get_active_peers(self):
        from alive.network.discovery import PeerRegistry

        reg = PeerRegistry()
        ann = {"agent": {"agent_id": "alp-1", "alias": "a"}, "port": 8484}
        reg.register("1.1.1.1", ann)
        peers = reg.get_active_peers(timeout=30)
        assert len(peers) == 1
        assert peers[0]["ip"] == "1.1.1.1"

    def test_expired_peers_excluded(self):
        from alive.network.discovery import PeerRegistry

        reg = PeerRegistry()
        ann = {"agent": {"agent_id": "alp-old", "alias": "old"}, "port": 8484}
        reg.register("1.1.1.1", ann)
        # Manually set last_seen to the past
        reg.peers["alp-old"]["last_seen"] = time.time() - 60
        peers = reg.get_active_peers(timeout=30)
        assert len(peers) == 0

    def test_permanent_peers_never_expire(self):
        from alive.network.discovery import PeerRegistry

        reg = PeerRegistry()
        card = {"agent_id": "alp-perm", "alias": "perm"}
        reg.add_manual("1.1.1.1", 8484, card)
        # Set last_seen to the past
        reg.peers["alp-perm"]["last_seen"] = time.time() - 9999
        peers = reg.get_active_peers(timeout=30)
        assert len(peers) == 1

    def test_cleanup_removes_expired(self):
        from alive.network.discovery import PeerRegistry

        reg = PeerRegistry()
        ann = {"agent": {"agent_id": "alp-gone", "alias": "g"}, "port": 8484}
        reg.register("1.1.1.1", ann)
        reg.peers["alp-gone"]["last_seen"] = time.time() - 60
        reg.cleanup(timeout=30)
        assert "alp-gone" not in reg.peers

    def test_cleanup_keeps_permanent(self):
        from alive.network.discovery import PeerRegistry

        reg = PeerRegistry()
        reg.add_manual("1.1.1.1", 8484, {"agent_id": "alp-p", "alias": "p"})
        reg.peers["alp-p"]["last_seen"] = time.time() - 9999
        reg.cleanup(timeout=30)
        assert "alp-p" in reg.peers

    def test_find_peer_by_alias(self):
        from alive.network.discovery import PeerRegistry

        reg = PeerRegistry()
        ann = {"agent": {"agent_id": "alp-abc", "alias": "darsh"}, "port": 8484}
        reg.register("1.1.1.1", ann)
        found = reg.find_peer("@darsh")
        assert found is not None
        assert found["agent"]["alias"] == "darsh"

    def test_find_peer_by_id_prefix(self):
        from alive.network.discovery import PeerRegistry

        reg = PeerRegistry()
        ann = {"agent": {"agent_id": "alp-abc123", "alias": "x"}, "port": 8484}
        reg.register("1.1.1.1", ann)
        found = reg.find_peer("alp-abc")
        assert found is not None

    def test_find_peer_not_found(self):
        from alive.network.discovery import PeerRegistry

        reg = PeerRegistry()
        assert reg.find_peer("nobody") is None

    def test_add_manual(self):
        from alive.network.discovery import PeerRegistry

        reg = PeerRegistry()
        card = {"agent_id": "alp-manual", "alias": "m", "skill_count": 10}
        reg.add_manual("10.0.0.1", 9000, card)
        assert "alp-manual" in reg.peers
        p = reg.peers["alp-manual"]
        assert p["permanent"] is True
        assert p["port"] == 9000


class TestConnectToPeer:
    def test_connect_success(self):
        from alive.network.discovery import connect_to_peer, PeerRegistry

        mock_card = {"agent_id": "alp-remote", "alias": "remote", "skill_count": 3}
        registry = PeerRegistry()

        with patch("alive.network.discovery.get_peer_registry", return_value=registry), \
             patch("httpx.get") as mock_get, \
             patch("alive.network.conversation_log.log_event"):
            mock_resp = MagicMock()
            mock_resp.json.return_value = mock_card
            mock_resp.raise_for_status = MagicMock()
            mock_get.return_value = mock_resp

            card = connect_to_peer("192.168.1.50:8585")
            assert card is not None
            assert card["agent_id"] == "alp-remote"
            assert "alp-remote" in registry.peers

    def test_connect_failure(self):
        from alive.network.discovery import connect_to_peer

        with patch("httpx.get", side_effect=Exception("timeout")), \
             patch("alive.network.conversation_log.log_event"):
            card = connect_to_peer("bad:9999")
            assert card is None

    def test_connect_default_port(self):
        from alive.network.discovery import connect_to_peer, PeerRegistry
        registry = PeerRegistry()

        with patch("alive.network.discovery.get_peer_registry", return_value=registry), \
             patch("httpx.get") as mock_get, \
             patch("alive.network.conversation_log.log_event"):
            mock_resp = MagicMock()
            mock_resp.json.return_value = {"agent_id": "alp-x", "alias": "x"}
            mock_resp.raise_for_status = MagicMock()
            mock_get.return_value = mock_resp

            connect_to_peer("10.0.0.1")
            mock_get.assert_called_once_with(
                "http://10.0.0.1:8484/alp/card", timeout=30
            )
