"""No network: verify the existing five clients' Story budget and private response handling."""
import importlib
import json
import os
import sys
import unittest
from unittest import mock

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(ROOT, 'scripts', 'game_harness'))
import env
env.install()

import requests
import xbmcaddon
from wcs.ai import model_catalog


class TransportTests(unittest.TestCase):
    def test_story_output_budget_and_private_json_across_existing_clients(self):
        answer = '{"schema_version":1,"status":"unavailable","reason":"test"}'
        payload = {'output': [{'type': 'message', 'content': [{'type': 'output_text', 'text': answer}]}],
                   'content': [{'type': 'thinking', 'thinking': 'hidden'}, {'type': 'text', 'text': answer}],
                   'choices': [{'message': {'content': answer}}],
                   'candidates': [{'content': {'parts': [{'text': answer}]}}],
                   'stop_reason': 'end_turn', 'usage': {}, 'usageMetadata': {}}
        response = mock.Mock(status_code=200, text=json.dumps(payload))
        response.json.return_value = payload

        class Addon:
            def getSetting(self, key):
                if key.endswith('_api_key'):
                    return 'offline-test-key'
                if 'max_tokens' in key or 'max_output_tokens' in key:
                    return '2048'
                return ''
            def getLocalizedString(self, key):
                return str(key)

        for provider, module_name in (('openai', 'OpenAIClient'), ('anthropic', 'AnthropicClient'),
                                      ('google', 'GoogleClient'), ('mistral', 'MistralClient'), ('groq', 'GroqClient')):
            with self.subTest(provider=provider):
                client = importlib.import_module('wcs.ai.' + module_name)
                with mock.patch.object(xbmcaddon, 'Addon', lambda *args: Addon()), \
                        mock.patch.object(requests, 'post', return_value=response) as post, \
                        mock.patch.object(client, 'show_api_request_debug') as debug_request, \
                        mock.patch.object(client, 'show_api_response_debug') as debug_response:
                    text, _usage = client.send_prompt('Return JSON.', model=model_catalog.MODELS[provider][0],
                                                      system_prompt='A private story.', json_mode=True,
                                                      max_output_tokens=16000, private_content=True)
                    self.assertEqual(text, answer)
                    sent = post.call_args.kwargs['json']
                    actual_budget = (sent['generationConfig']['maxOutputTokens'] if provider == 'google' else
                                     sent['max_output_tokens'] if provider == 'openai' else sent['max_tokens'])
                    self.assertEqual(actual_budget, 16000)
                    self.assertNotIn('private_content', sent)
                    debug_request.assert_not_called()
                    debug_response.assert_not_called()
                    self.assertEqual(post.call_count, 1)
                    if provider in ('openai', 'anthropic'):
                        self.assertEqual(post.call_args.kwargs['timeout'], 120 if provider == 'openai' else 180)
                        client.send_prompt('Return JSON.', model=model_catalog.MODELS[provider][0],
                                           json_mode=True, max_output_tokens=32000,
                                           request_timeout=300, private_content=True)
                        sent = post.call_args.kwargs['json']
                        self.assertEqual(post.call_args.kwargs['timeout'], 300)
                        self.assertEqual(sent['max_output_tokens' if provider == 'openai' else 'max_tokens'], 32000)
                        self.assertNotIn('request_timeout', sent)
                        self.assertEqual(post.call_count, 2)
                        debug_request.assert_not_called()
                        debug_response.assert_not_called()


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