import asyncio
import os
from unittest.mock import AsyncMock, patch

import litellm
import pytest
from fastapi.testclient import TestClient

from litellm.llms.base_llm.ocr.transformation import OCRPage, OCRResponse, OCRUsageInfo
from litellm.proxy.proxy_server import app, initialize


@pytest.fixture(scope="function")
def fake_env_vars(monkeypatch):
    monkeypatch.setenv("OPENAI_API_KEY", "fake_openai_api_key")
    monkeypatch.setenv("OPENAI_API_BASE", "http://fake-openai-api-base")
    monkeypatch.setenv("AZURE_AI_API_BASE", "http://fake-azure-api-base")
    monkeypatch.setenv("AZURE_AI_API_KEY", "fake_azure_api_key")
    monkeypatch.setenv("AZURE_OPENAI_API_KEY", "fake_azure_openai_api_key")
    monkeypatch.setenv("AZURE_SWEDEN_API_BASE", "http://fake-azure-sweden-api-base")
    monkeypatch.setenv("AZURE_SWEDEN_API_KEY", "fake_azure_sweden_api_key")
    monkeypatch.setenv("REDIS_HOST", "localhost")


@pytest.fixture(scope="function")
def client_no_auth(fake_env_vars):
    from litellm.proxy.proxy_server import cleanup_router_config_variables

    original_disable_aiohttp = litellm.disable_aiohttp_transport
    litellm.disable_aiohttp_transport = True
    litellm.in_memory_llm_clients_cache.flush_cache()
    cleanup_router_config_variables()

    filepath = os.path.dirname(os.path.abspath(__file__))
    config_fp = os.path.join(filepath, "test_configs", "test_config_no_auth.yaml")
    asyncio.run(initialize(config=config_fp, debug=True))

    # Passthrough of api_base in the JSON body is rejected by default
    # (pre_db_read_auth_checks / is_request_body_safe). This test asserts
    # api_base reaches aocr().
    from litellm.proxy import proxy_server as _ps

    if _ps.general_settings is None:
        _ps.general_settings = {}
    _ps.general_settings["allow_client_side_credentials"] = True

    try:
        yield TestClient(app)
    finally:
        litellm.disable_aiohttp_transport = original_disable_aiohttp
        litellm.in_memory_llm_clients_cache.flush_cache()


def test_proxy_reducto_ocr_json_rejects_reducto_id(client_no_auth):
    with patch(
        "litellm.proxy.proxy_server.llm_router.aocr",
        new=AsyncMock(),
    ) as mock_aocr:
        response = client_no_auth.post(
            "/v1/ocr",
            json={
                "model": "reducto/parse-v3",
                "document": {
                    "type": "document_url",
                    "document_url": "reducto://proxy.pdf",
                },
                "api_key": "proxy-key",
                "api_base": "https://platform.reducto.ai",
            },
        )

    assert response.status_code >= 400
    assert "reducto://" in response.text
    assert mock_aocr.await_count == 0


def test_proxy_reducto_ocr_json_rejects_reducto_id_in_image_url(client_no_auth):
    with patch(
        "litellm.proxy.proxy_server.llm_router.aocr",
        new=AsyncMock(),
    ) as mock_aocr:
        response = client_no_auth.post(
            "/v1/ocr",
            json={
                "model": "reducto/parse-v3",
                "document": {
                    "type": "image_url",
                    "image_url": "reducto://proxy.png",
                },
            },
        )

    assert response.status_code >= 400
    assert "reducto://" in response.text
    assert mock_aocr.await_count == 0


def test_proxy_reducto_ocr_json_passthrough_data_uri(client_no_auth):
    mocked_response = OCRResponse(
        pages=[OCRPage(index=0, markdown="Proxy OCR")],
        model="parse-v3",
        usage_info=OCRUsageInfo(pages_processed=1, credits=1),
    )

    data_uri = "data:application/pdf;base64,JVBERi0xLjQK"

    with patch(
        "litellm.proxy.proxy_server.llm_router.aocr",
        new=AsyncMock(return_value=mocked_response),
    ) as mock_aocr:
        response = client_no_auth.post(
            "/v1/ocr",
            json={
                "model": "reducto/parse-v3",
                "document": {
                    "type": "document_url",
                    "document_url": data_uri,
                },
                "api_key": "proxy-key",
                "api_base": "https://platform.reducto.ai",
            },
        )

    assert response.status_code == 200
    assert mock_aocr.await_count == 1
    assert mock_aocr.await_args.kwargs["model"] == "reducto/parse-v3"
    assert mock_aocr.await_args.kwargs["document"] == {
        "type": "document_url",
        "document_url": data_uri,
    }
    assert mock_aocr.await_args.kwargs["api_key"] == "proxy-key"
    assert mock_aocr.await_args.kwargs["api_base"] == "https://platform.reducto.ai"

    response_body = response.json()
    assert response_body["object"] == "ocr"
    assert response_body["usage_info"]["credits"] == 1
    assert response_body["pages"][0]["markdown"] == "Proxy OCR"
