"""Tests for task-based routing added to _try_docuvision()."""
from __future__ import annotations

from unittest.mock import MagicMock, patch


def _mock_doc_result(text: str = "RECEIPT TEXT") -> MagicMock:
    r = MagicMock()
    r.text = text
    return r


def _make_task_ctx(url: str = "http://node:9010") -> MagicMock:
    alloc = MagicMock()
    alloc.url = url
    alloc.allocation_id = "alloc-vis-1"
    alloc.service = "cf-docuvision"
    ctx = MagicMock()
    ctx.__enter__ = MagicMock(return_value=alloc)
    ctx.__exit__ = MagicMock(return_value=False)
    return ctx


def _make_task_not_registered() -> MagicMock:
    from app.services.task_inference import TaskNotRegistered
    ctx = MagicMock()
    ctx.__enter__ = MagicMock(side_effect=TaskNotRegistered("not registered"))
    ctx.__exit__ = MagicMock(return_value=False)
    return ctx


def _make_direct_alloc(url: str = "http://node:9011") -> MagicMock:
    alloc = MagicMock()
    alloc.url = url
    ctx = MagicMock()
    ctx.__enter__ = MagicMock(return_value=alloc)
    ctx.__exit__ = MagicMock(return_value=False)
    return ctx


def test_try_docuvision_task_path_returns_text(monkeypatch, tmp_path):
    """_try_docuvision() uses task allocation and returns extracted text on success."""
    monkeypatch.setenv("CF_ORCH_URL", "http://coord:7700")
    fake_image = tmp_path / "receipt.jpg"
    fake_image.write_bytes(b"fake")

    with patch("app.services.task_inference.task_allocate",
               return_value=_make_task_ctx(url="http://node:9010")), \
         patch("app.services.ocr.docuvision_client.DocuvisionClient") as MockDoc:
        MockDoc.return_value.extract_text.return_value = _mock_doc_result("STORE $12.34")
        from app.services.ocr.vl_model import _try_docuvision
        result = _try_docuvision(str(fake_image))

    assert result == "STORE $12.34"
    MockDoc.assert_called_once_with("http://node:9010")


def test_try_docuvision_falls_back_to_direct_on_task_not_registered(monkeypatch, tmp_path):
    """_try_docuvision() falls back to direct cf-docuvision allocation on TaskNotRegistered."""
    monkeypatch.setenv("CF_ORCH_URL", "http://coord:7700")
    fake_image = tmp_path / "receipt.jpg"
    fake_image.write_bytes(b"fake")

    with patch("app.services.task_inference.task_allocate",
               return_value=_make_task_not_registered()), \
         patch("circuitforge_orch.client.CFOrchClient") as MockClient, \
         patch("app.services.ocr.docuvision_client.DocuvisionClient") as MockDoc:
        MockClient.return_value.allocate.return_value = _make_direct_alloc("http://node:9011")
        MockDoc.return_value.extract_text.return_value = _mock_doc_result("FALLBACK TEXT")
        from app.services.ocr.vl_model import _try_docuvision
        result = _try_docuvision(str(fake_image))

    assert result == "FALLBACK TEXT"
    MockDoc.assert_called_once_with("http://node:9011")


def test_try_docuvision_returns_none_without_cf_orch_url(monkeypatch, tmp_path):
    """_try_docuvision() returns None immediately when CF_ORCH_URL is not set."""
    monkeypatch.delenv("CF_ORCH_URL", raising=False)
    fake_image = tmp_path / "receipt.jpg"
    fake_image.write_bytes(b"fake")

    from app.services.ocr.vl_model import _try_docuvision
    result = _try_docuvision(str(fake_image))

    assert result is None
