"""
Unit tests for Multi-LLM Provider Client Engine in FreeExile.
Verifies integration and communication contracts with OpenRouter, OpenAI (GPT),
Anthropic (Claude), Google (Gemini), DeepSeek, Moonshot (Kimi), and Local Tactical Fallback.
"""

import unittest
import asyncio
import sys
import os

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

from agent.llm_provider_client import (
    LLMProviderType,
    LLMProviderConfig,
    AgentActionType,
    TacticalActionDecision,
    LLMProviderClientRouter
)


class TestLLMProviderClient(unittest.TestCase):
    def setUp(self):
        self.router = LLMProviderClientRouter()

    def test_provider_enum_definitions(self):
        """Verifies that all 6 requested cloud LLM providers plus local tactical are recognized."""
        expected_providers = {
            LLMProviderType.OPENROUTER,
            LLMProviderType.OPENAI,
            LLMProviderType.ANTHROPIC,
            LLMProviderType.GEMINI,
            LLMProviderType.DEEPSEEK,
            LLMProviderType.KIMI,
            LLMProviderType.LOCAL_TACTICAL,
        }
        for prov in expected_providers:
            self.assertIn(prov, list(LLMProviderType))

    def test_default_endpoint_and_model_mapping(self):
        """Verifies default base URLs and recommended models for each provider."""
        config_openrouter = LLMProviderConfig(provider=LLMProviderType.OPENROUTER, api_key="sk-or-test")
        self.assertEqual(config_openrouter.model, "meta-llama/llama-3.3-70b-instruct")
        self.assertIn("openrouter.ai", config_openrouter.base_url)

        config_deepseek = LLMProviderConfig(provider=LLMProviderType.DEEPSEEK, api_key="sk-ds-test")
        self.assertEqual(config_deepseek.model, "deepseek-chat")
        self.assertIn("deepseek.com", config_deepseek.base_url)

        config_kimi = LLMProviderConfig(provider=LLMProviderType.KIMI, api_key="sk-km-test")
        self.assertEqual(config_kimi.model, "moonshot-v1-8k")
        self.assertIn("moonshot.cn", config_kimi.base_url)

        config_gemini = LLMProviderConfig(provider=LLMProviderType.GEMINI, api_key="sk-gm-test")
        self.assertIn("gemini", config_gemini.model)

    def test_local_tactical_heuristic_fallback(self):
        """When in LOCAL_TACTICAL mode or offline, decision must return deterministically without network call."""
        config = LLMProviderConfig(provider=LLMProviderType.LOCAL_TACTICAL)
        world_prompt = {
            "player_hp_pct": 0.20,
            "nearby_enemies": [{"id": 101, "distance": 2.0, "element": "THO"}],
            "nearby_drops": [{"id": "drop_1", "item": "curr_chaos_stone", "distance": 1.5}]
        }

        decision = asyncio.run(self.router.request_tactical_decision(config, world_prompt))
        self.assertIsInstance(decision, TacticalActionDecision)
        # Low HP (20%) must trigger defensive or dodge reaction
        self.assertIn(decision.action_type, [AgentActionType.DODGE, AgentActionType.USE_POTION, AgentActionType.MOVE_AWAY])
        self.assertTrue(len(decision.reasoning) > 0)

    def test_structured_json_action_parsing(self):
        """Verifies that structured JSON responses from LLMs parse cleanly into TacticalActionDecision."""
        raw_llm_json = """
        {
            "action_type": "ATTACK_SKILL",
            "target_id": 99,
            "skill_id": 102,
            "target_x": 12.5,
            "target_y": -4.2,
            "reasoning": "Target is Earth element. Switching to Wood sword skill for elemental counter advantage."
        }
        """
        decision = self.router.parse_response_to_decision(raw_llm_json)
        self.assertEqual(decision.action_type, AgentActionType.ATTACK_SKILL)
        self.assertEqual(decision.target_id, 99)
        self.assertEqual(decision.skill_id, 102)
        self.assertIn("Earth element", decision.reasoning)

    def test_provider_headers_generation(self):
        """Verifies correct Authorization headers for Anthropic, OpenRouter, and standard Bearer."""
        conf_anthropic = LLMProviderConfig(provider=LLMProviderType.ANTHROPIC, api_key="sk-ant-12345")
        headers_ant = self.router.build_request_headers(conf_anthropic)
        self.assertEqual(headers_ant.get("x-api-key"), "sk-ant-12345")
        self.assertIn("anthropic-version", headers_ant)

        conf_openrouter = LLMProviderConfig(provider=LLMProviderType.OPENROUTER, api_key="sk-or-12345")
        headers_or = self.router.build_request_headers(conf_openrouter)
        self.assertEqual(headers_or.get("Authorization"), "Bearer sk-or-12345")
        self.assertIn("HTTP-Referer", headers_or)


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