"""
Unit tests for Network Gateway Session Management & Framing in FreeExile.
Verifies session creation, heartbeat timeout eviction, packet framing, and envelope dispatch.
"""

import unittest
import sys
import os
import time

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../server")))

from gateway.session_manager import SessionManager, ClientSession
from gateway.network_gateway import PacketCodec


class TestNetworkGateway(unittest.TestCase):
    def setUp(self):
        self.session_mgr = SessionManager(session_timeout_seconds=2.0)

    def test_session_lifecycle(self):
        """Registering, retrieving, and terminating a client session."""
        session = self.session_mgr.create_session(
            account_id="acc_iphone_user_1",
            entity_id=1001,
            client_ip="192.168.1.50"
        )
        self.assertIsNotNone(session.session_id)
        self.assertEqual(session.entity_id, 1001)

        retrieved = self.session_mgr.get_session(session.session_id)
        self.assertEqual(retrieved, session)

        # Heartbeat update
        self.session_mgr.record_heartbeat(session.session_id, latency_ms=18.5)
        self.assertEqual(session.last_latency_ms, 18.5)

        # Termination
        self.session_mgr.remove_session(session.session_id)
        self.assertIsNone(self.session_mgr.get_session(session.session_id))

    def test_heartbeat_timeout_eviction(self):
        """Stale sessions without heartbeats within timeout period get evicted."""
        session = self.session_mgr.create_session("acc_2", 1002, "127.0.0.1")
        # Artificially set last heartbeat to 5 seconds ago
        session.last_heartbeat_timestamp = time.time() - 5.0

        evicted = self.session_mgr.evict_stale_sessions()
        self.assertIn(session.session_id, evicted)
        self.assertIsNone(self.session_mgr.get_session(session.session_id))

    def test_packet_framing_encode_decode(self):
        """Codec correctly encodes 4-byte length prefix and decodes complete frames."""
        payload = b"FREEEXILE_FRAME_DATA"
        framed_data = PacketCodec.encode_frame(payload)
        
        # 4-byte length prefix + payload
        self.assertEqual(len(framed_data), 4 + len(payload))

        decoded_payload, remainder = PacketCodec.decode_frame(framed_data)
        self.assertEqual(decoded_payload, payload)
        self.assertEqual(remainder, b"")


if __name__ == "__main__":
    unittest.main()
