"""
Unit tests for Server-Authoritative Movement and Anti-Speedhack in FreeExile.
Verifies valid velocity integration, speedhack rejection, rubberbanding, and suspicion scoring.
"""

import unittest
import sys
import os

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

from world.movement_authority import MovementAuthorityEngine, PlayerCharacter


class TestMovementAuthority(unittest.TestCase):
    def setUp(self):
        # Base speed 6.0 m/s (standard PoE2/VLTK1 movement pace)
        self.engine = MovementAuthorityEngine(max_base_speed=6.0, tolerance_multiplier=1.15)
        self.player = PlayerCharacter(
            entity_id=101,
            x=0.0,
            y=0.0,
            move_speed=6.0
        )
        self.engine.register_player(self.player)

    def test_valid_movement_step(self):
        """Player moves in direction (1.0, 0.0) over 0.1s (100ms tick)."""
        dt = 0.1
        # Expected max travel: 6.0 * 0.1 = 0.60m
        valid, new_x, new_y = self.engine.process_move_input(
            entity_id=101,
            dir_x=1.0,
            dir_y=0.0,
            dt=dt
        )
        self.assertTrue(valid)
        self.assertAlmostEqual(new_x, 0.60, places=2)
        self.assertAlmostEqual(new_y, 0.0, places=2)
        self.assertEqual(self.player.suspicion_score, 0)

    def test_speedhack_injection_rejected(self):
        """Client attempts to move 5.0m in a 0.1s tick (50 m/s, nearly 10x max speed)."""
        dt = 0.1
        # Attacker injects a movement request exceeding max threshold
        valid, new_x, new_y = self.engine.validate_and_reconcile_position(
            entity_id=101,
            claimed_x=5.0,
            claimed_y=0.0,
            dt=dt
        )
        self.assertFalse(valid)
        # Position must be rubberbanded back to original authoritative position (0.0, 0.0)
        self.assertEqual(new_x, 0.0)
        self.assertEqual(new_y, 0.0)
        self.assertGreater(self.player.suspicion_score, 0)


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