# /var/www/html/flask_server/shared/openai_manager.py
import base64
import json
import os

def run_vision_json(*, model: str, prompt: str, file_bytes: bytes, filename: str = "", mimetype: str = "application/octet-stream"):
    """
    Interfaz estable para toda la plataforma.
    - JPG/PNG directo; si es PDF intenta convertir 1ª página a PNG con PyMuPDF si está disponible.
    - Usa SOLO chat.completions; sin 'temperature'.
    - Primer intento con response_format JSON; si el SDK/modelo no lo soporta, reintenta sin response_format
      y fuerza JSON por prompt.
    Devuelve dict (parse de JSON); si el modelo devuelve texto no-JSON en el fallback, retorna {"_raw": "..."}.
    """
    # PDF → imagen (si posible)
    if mimetype.lower().endswith("pdf") or mimetype.lower() == "application/pdf":
        try:
            import fitz  # PyMuPDF
            doc = fitz.open(stream=file_bytes, filetype="pdf")
            page = doc.load_page(0)
            dpi = int(os.getenv("WP_INVOICES_DEFAULT_DPI", "220"))
            pix = page.get_pixmap(dpi=dpi)
            file_bytes = pix.tobytes("png")
            mimetype = "image/png"
        except Exception:
            # Si no se puede, seguimos con data URI del PDF (algunos modelos lo soportan)
            pass

    try:
        from openai import OpenAI, BadRequestError
    except Exception as e:
        raise ImportError("openai SDK no instalado o incompatible.") from e

    client = OpenAI()

    b64 = base64.b64encode(file_bytes).decode("utf-8")
    data_url = f"data:{mimetype};base64,{b64}"

    # Contenido con imagen
    content = [
        {"type": "text", "text": prompt},
        {"type": "image_url", "image_url": {"url": data_url}},
    ]

    # 1) Intento con response_format JSON (sin temperature)
    try:
        resp = client.chat.completions.create(
            model=model,
            messages=[{"role": "user", "content": content}],
            response_format={"type": "json_object"},
        )
        text = resp.choices[0].message.content
        return json.loads(text) if isinstance(text, str) else text
    except BadRequestError as e:
        # Algunos modelos/SDK no soportan response_format → reintentar sin él
        pass
    except Exception:
        # Cualquier otra excepción → también probamos el fallback sin response_format
        pass

    # 2) Fallback sin response_format: reforzar en el prompt que SOLO devuelva JSON estricto
    fallback_prompt = (
        "Responde ÚNICAMENTE con un objeto JSON válido, sin comentarios ni texto extra.\n\n" + prompt
    )
    content_fallback = [
        {"type": "text", "text": fallback_prompt},
        {"type": "image_url", "image_url": {"url": data_url}},
    ]

    resp = client.chat.completions.create(
        model=model,
        messages=[{"role": "user", "content": content_fallback}],
        # sin temperature, sin response_format
    )
    text = resp.choices[0].message.content
    try:
        return json.loads(text) if isinstance(text, str) else text
    except Exception:
        # Último recurso: regresamos lo crudo para inspección
        return {"_raw": text}
