"""Exercise the real SDK against a loopback fixture; no model provider is called."""
import json
import threading
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

import litelm
from litelm.providers._anthropic import _translate_messages

requests = []


class Fixture(BaseHTTPRequestHandler):
    def log_message(self, *args):
        pass

    def do_POST(self):
        body = json.loads(self.rfile.read(int(self.headers['Content-Length'])))
        requests.append({'path': self.path, 'body': body})
        if body['model'] == 'fixture-down':
            status = 429
            payload = {'error': {'message': 'fixture rate limit', 'type': 'rate_limit_error', 'code': 'rate_limit'}}
        else:
            status = 200
            has_result = any(m['role'] == 'tool' for m in body['messages'])
            message = {'role': 'assistant', 'content': '14 passed, 1 failed'} if has_result else {
                'role': 'assistant', 'content': None, 'tool_calls': [{
                    'id': 'call_42', 'type': 'function',
                    'function': {'name': 'test_summary', 'arguments': '{"suite":"unit"}'},
                }],
            }
            payload = {
                'id': 'chatcmpl-fixture', 'object': 'chat.completion', 'created': 0,
                'model': body['model'], 'choices': [{'index': 0, 'message': message,
                    'finish_reason': 'stop' if has_result else 'tool_calls'}],
                'usage': {'prompt_tokens': 10, 'completion_tokens': 5, 'total_tokens': 15},
            }
        encoded = json.dumps(payload).encode()
        self.send_response(status)
        self.send_header('Content-Type', 'application/json')
        self.send_header('Content-Length', str(len(encoded)))
        self.end_headers()
        self.wfile.write(encoded)


server = ThreadingHTTPServer(('127.0.0.1', 0), Fixture)
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
kwargs = {'api_key': 'fixture-key', 'api_base': f'http://127.0.0.1:{server.server_port}/v1', 'num_retries': 0}
try:
    messages = [{'role': 'user', 'content': 'Read the unit test summary.'}]
    tools = [{'type': 'function', 'function': {'name': 'test_summary',
        'parameters': {'type': 'object', 'properties': {'suite': {'type': 'string'}}, 'required': ['suite']}}}]
    response = litelm.completion('openai/fixture-model', messages=messages, tools=tools,
                                tool_choice='required', **kwargs)
    call = response.choices[0].message.tool_calls[0]
    assert call.id == 'call_42'
    assert json.loads(call.function.arguments) == {'suite': 'unit'}
    messages += [response.choices[0].message.model_dump(exclude_none=True),
                 {'role': 'tool', 'tool_call_id': call.id, 'content': '{"passed":14,"failed":1}'}]
    response = litelm.completion('openai/fixture-model', messages=messages, **kwargs)
    assert response.choices[0].message.content == '14 passed, 1 failed'
    assert [r['path'] for r in requests] == ['/v1/chat/completions'] * 2
    assert requests[0]['body']['model'] == 'fixture-model'
    print('tool round-trip: 2 HTTP requests, call_42 preserved, arguments parsed')
    print('normalized response:', response.choices[0].message.content)
    print('second request tool message:', json.dumps(requests[1]['body']['messages'][-1], separators=(',', ':')))

    translated = _translate_messages(messages)
    use = translated[1]['content'][0]
    result = translated[2]['content'][0]
    assert use['id'] == result['tool_use_id'] == 'call_42'
    assert use['input'] == {'suite': 'unit'}
    print('Anthropic translation:', json.dumps([translated[1], translated[2]], separators=(',', ':')))

    start = len(requests)
    try:
        litelm.completion('openai/fixture-down', messages=messages,
                          fallbacks=['openai/fixture-model'], **kwargs)
    except litelm.RateLimitError:
        assert len(requests) - start == 1
        assert requests[-1]['body']['model'] == 'fixture-down'
        assert 'fallbacks' not in requests[-1]['body']
        print('fallback probe: RateLimitError, 1 HTTP request, no fallback attempted')
    else:
        raise AssertionError('expected fixture rate-limit error')
finally:
    server.shutdown()
    server.server_close()
    thread.join()
