#!/usr/bin/env python3
"""Ejecuta una consulta en Responses API y conserva sus búsquedas observables.

Uso: OPENAI_API_KEY=... python3 extraer-fan-out.py --prompt "..." --salida prueba
Requiere requests. La API tiene facturación independiente de ChatGPT.
"""
import argparse
import json
import os
from datetime import datetime, timezone
from pathlib import Path

import requests


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('--prompt', required=True)
    parser.add_argument('--modelo', default='gpt-5.5')
    parser.add_argument('--salida', type=Path, required=True)
    args = parser.parse_args()
    key = os.environ.get('OPENAI_API_KEY')
    if not key:
        parser.error('Falta OPENAI_API_KEY en el entorno.')
    # Directorio exclusivo: evita sobrescribir resultados de otra ejecución.
    args.salida.mkdir(parents=True, exist_ok=False)
    request = {
        'model': args.modelo,
        'input': args.prompt,
        'tools': [{'type': 'web_search'}],
        'tool_choice': 'required',
        'include': ['web_search_call.action.sources'],
        'max_tool_calls': 6,
        'max_output_tokens': 6000,
        'store': False,
    }
    endpoint = 'https://api.openai.com/v1/responses'
    assert endpoint.startswith('https://api.openai.com/'), 'Destino no permitido'
    started = datetime.now(timezone.utc).isoformat()
    response = requests.post(endpoint, headers={'Authorization': f'Bearer {key}'},
                             json=request, timeout=240)
    if not response.ok:
        # No se guardan cabeceras ni claves ni cuerpos de error con información de cuenta.
        raise SystemExit(f'Error HTTP {response.status_code}; revisa acceso, modelo y saldo.')
    data = response.json()
    calls = []
    citations = []
    answer = []
    for item in data.get('output', []):
        if item.get('type') == 'web_search_call':
            action = item.get('action') or {}
            queries = action.get('queries') or []
            if isinstance(queries, str):
                queries = [queries]
            if not queries and action.get('query'):
                queries = [action['query']]
            calls.append({'id': item.get('id'), 'status': item.get('status'),
                          'action': action, 'queries_observadas': queries,
                          'consultas_expuestas': bool(queries) if action.get('type') == 'search' else None})
        if item.get('type') == 'message':
            for content in item.get('content', []):
                if content.get('type') == 'output_text':
                    answer.append(content.get('text', ''))
                    citations.extend(a for a in content.get('annotations', [])
                                     if a.get('type') == 'url_citation')
    result = {'fecha_utc': started, 'superficie': 'OpenAI Responses API (no ChatGPT web)',
              'modelo_solicitado': args.modelo, 'modelo_devuelto': data.get('model'),
              'prompt': args.prompt, 'estado': data.get('status'),
              'incomplete_details': data.get('incomplete_details'),
              'llamadas_web': calls, 'citas_respuesta': citations,
              'usage': data.get('usage'),
              'limite': 'Solo lo expuesto por esta ejecución. Ausencia del campo queries no prueba ausencia de búsqueda.'}
    for name, obj in [('peticion.json', request), ('respuesta-api.json', data), ('fan-out.json', result)]:
        (args.salida / name).write_text(json.dumps(obj, ensure_ascii=False, indent=2))
    (args.salida / 'respuesta.md').write_text('\n\n'.join(answer))
    print(json.dumps(result, ensure_ascii=False, indent=2))


if __name__ == '__main__':
    main()
