import unittest
import sys
import os
import time

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

from world.server_engine_loop import ServerEngineLoop
from world.martial_matrix import FiveElements
from world.agent_orb_service import (
    AgentOrbService,
    AgentOrbTier,
    DelegationSession,
    DelegationHarvestReport
)
from agent.agent_decision_core import TacticalStance
from agent.llm_provider_client import LLMProviderType, LLMProviderConfig

import hmac
import hashlib
import json

class TestAgentOrbHMAC(unittest.TestCase):
    def setUp(self):
        self.engine = ServerEngineLoop()
        self.service = AgentOrbService(engine=self.engine, db_path=":memory:")
        self.engine.register_player(
            entity_id=1,
            initial_x=0.0,
            initial_y=0.0,
            initial_z=0.0,
            element=FiveElements.HOA,
            move_speed=6.0,
            max_hp=1000.0
        )
        self.service.grant_agent_orb(player_id=1, orb_id="item_agent_orb_tier1", count=1)

    def test_reclaim_control_hmac_signature(self):
        cfg = LLMProviderConfig(provider=LLMProviderType.LOCAL_TACTICAL)
        self.service.activate_delegation(1, "item_agent_orb_tier1", TacticalStance.TREASURE_HUNTER, cfg)
        self.service.record_loot_harvest(1, "curr_chaos_stone", 5)
        self.service.record_monster_slain(1, exp=8500)

        report = self.service.reclaim_control(player_id=1)
        self.assertIsInstance(report, DelegationHarvestReport)
        
        # Verify HMAC
        self.assertTrue(hasattr(report, 'hmac_signature'))
        self.assertNotEqual(report.hmac_signature, "")

        # Manually reconstruct
        secret_key = os.environ.get("AGENT_HMAC_SECRET", "default_freeexile_secret").encode("utf-8")
        drops_str = json.dumps(report.spirit_stones_looted, sort_keys=True)
        payload = f"{report.session_id}{report.exp_gained}{drops_str}{report.reclaimed_timestamp}".encode("utf-8")
        expected_sig = hmac.new(secret_key, payload, hashlib.sha256).hexdigest()
        
        self.assertEqual(report.hmac_signature, expected_sig)
        self.assertTrue(self.service.validate_harvest_report(report))
        
        # Tamper report and ensure it fails validation
        tampered_report = DelegationHarvestReport(
            session_id=report.session_id,
            player_id=report.player_id,
            total_duration_sec=report.total_duration_sec,
            actual_active_time_sec=report.actual_active_time_sec,
            exp_gained=report.exp_gained + 10000,
            monsters_slain=report.monsters_slain,
            spirit_stones_looted=report.spirit_stones_looted.copy(),
            potions_consumed=report.potions_consumed,
            reclaimed_timestamp=report.reclaimed_timestamp,
            hmac_signature=report.hmac_signature
        )
        self.assertFalse(self.service.validate_harvest_report(tampered_report))

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