"""A tool-calling agent that can only read a fictional inventory."""
import json
import os
import sys
from common import request_json

INVENTORY = {
    'keyboard': {'item': 'keyboard', 'price_eur': 49, 'stock': 12},
    'monitor': {'item': 'monitor', 'price_eur': 199, 'stock': 7},
    'mouse': {'item': 'mouse', 'price_eur': 25, 'stock': 0},
}
TOOLS = [{
    'type': 'function',
    'function': {
        'name': 'lookup_inventory',
        'description': 'Read the price and stock for keyboard, monitor, or mouse.',
        'parameters': {
            'type': 'object',
            'properties': {'item': {'type': 'string', 'enum': list(INVENTORY)}},
            'required': ['item'],
            'additionalProperties': False,
        },
    },
}]


def dispatch(call):
    function = call.get('function', {})
    if function.get('name') != 'lookup_inventory':
        raise ValueError('Unknown tool requested.')
    args = function.get('arguments')
    if not isinstance(args, dict) or set(args) != {'item'}:
        raise ValueError('Expected exactly one item argument.')
    item = args['item']
    if not isinstance(item, str) or item not in INVENTORY:
        raise ValueError('Unknown inventory item.')
    return dict(INVENTORY[item])


def run_agent(question, chat=request_json, trace=False, max_rounds=4):
    if not isinstance(question, str) or not question.strip():
        raise ValueError('Ask a non-empty question.')
    messages = [
        {'role': 'system', 'content': 'Use lookup_inventory for all stock and price questions. Do not guess inventory facts. Tools are read-only. Say when information is unavailable.'},
        {'role': 'user', 'content': question},
    ]
    calls_made = 0
    for _ in range(max_rounds):
        response = chat('chat', {
            'model': os.getenv('BLOG_CHAT_MODEL', 'qwen3:4b'),
            'stream': False, 'think': False, 'tools': TOOLS,
            'options': {'temperature': 0, 'num_ctx': 4096, 'num_predict': 400},
            'messages': messages,
        })
        message = response['message']
        messages.append(message)
        calls = message.get('tool_calls') or []
        if not calls:
            return {'answer': message.get('content', ''), 'tool_calls': calls_made}
        if not isinstance(calls, list) or len(calls) > 3:
            raise ValueError('Too many or malformed tool calls.')
        for call in calls:
            result = dispatch(call)
            calls_made += 1
            name = call['function']['name']
            if trace:
                print(f'TOOL {name}: {json.dumps(result)}', file=sys.stderr)
            messages.append({'role': 'tool', 'tool_name': name, 'content': json.dumps(result)})
    raise RuntimeError('Stopped after the tool-call round limit.')


if __name__ == '__main__':
    result = run_agent(' '.join(sys.argv[1:]) or 'How much is a monitor, and is it in stock?', trace=True)
    print(result['answer'])
