# #region Test.BatchProcessingService.Extra [C:3] [TYPE Module] [SEMANTICS test, batch, process, coverage]
# @BRIEF Additional coverage for BatchProcessingService edge cases.
# @RELATION BINDS_TO -> [BatchProcessingService]
# @TEST_EDGE: empty_source_text_cache -> continue on empty source_text in _check_cache
# @TEST_EDGE: provider_token_config_error -> Graceful fallback in _process_llm
# @TEST_EDGE: insert_batch_to_target_delegation -> Delegates to _batch_insert
import pytest
from unittest.mock import AsyncMock, MagicMock, patch

from src.models.translate import TranslationJob
from src.plugins.translate._batch_proc import BatchProcessingService

from .conftest import JOB_ID, RUN_ID


def _make_job(session, target_langs=None):
    job = session.query(TranslationJob).filter(TranslationJob.id == JOB_ID).first()
    if job is None:
        job = TranslationJob(
            id=JOB_ID, name="Batch Extra Test", source_dialect="en",
            target_dialect=target_langs[0] if target_langs else "fr",
            target_languages=target_langs or ["fr"],
            status="ACTIVE", provider_id="test-provider",
        )
        session.add(job)
    else:
        if target_langs:
            job.target_languages = target_langs
            job.target_dialect = target_langs[0]
        # Ensure provider_id is always set so _process_llm enters the try/except block
        job.provider_id = "test-provider"
    session.commit()
    return job


def _batch_rows(count=2, detected_lang="en"):
    return [
        {
            "row_index": str(i),
            "source_text": f"Hello world {i}",
            "source_data": {"table": "test", "row_id": i},
            "_detected_lang": detected_lang,
        }
        for i in range(count)
    ]


class TestCheckCacheEdgeCases:
    """Cover edge cases in _check_cache."""

    def test_empty_source_text_skips_cache(self, db_session):
        """When source_text is empty, continue without setting cache values."""
        config = MagicMock()
        svc = BatchProcessingService(db_session, config)
        job = _make_job(db_session)
        rows = [{"row_index": "0", "source_text": "", "_detected_lang": "en"}]

        svc._check_cache(job, rows, "hash1", "hash2")
        assert "_cached_lang_values" not in rows[0]
        # _source_hash is NOT set because empty text hits `if not st: continue`
        # (the hash is only computed when we proceed past the empty-text guard)
        # So we don't assert _source_hash — it's skipped for empty text


class TestProcessLlmEdgeCases:
    """Cover edge cases in _process_llm."""

    @pytest.mark.asyncio
    async def test_provider_token_config_error_graceful(self, db_with_run):
        """When get_provider_token_config raises, fall through gracefully."""
        session, run_id = db_with_run
        config = MagicMock()
        svc = BatchProcessingService(session, config)
        job = _make_job(session)
        rows = _batch_rows(1)

        with patch('src.plugins.translate._batch_proc.LLMProviderService') as MockProv:
            mock_prov_instance = MockProv.return_value
            mock_prov_instance.get_provider_token_config.side_effect = ValueError("DB error")
            with patch('src.plugins.translate._batch_proc.estimate_token_budget',
                       return_value={
                           "max_output_needed": 1000, "max_rows_by_output": 10,
                           "estimated_input_tokens": 500, "warning": None,
                       }):
                with patch.object(svc._llm_service, 'call_llm_for_batch',
                                  new=AsyncMock(return_value={"successful": 1, "failed": 0,
                                                               "skipped": 0, "retries": 0})):
                    result = await svc._process_llm(
                        job, run_id, rows, [], "batch-1", ["fr"],
                    )
                    assert result["successful"] == 1


class TestInsertBatchToTarget:
    """Cover insert_batch_to_target delegation."""

    @pytest.mark.asyncio
    async def test_delegates_to_batch_insert(self, db_with_run):
        """Ensure insert_batch_to_target delegates correctly."""
        session, run_id = db_with_run
        config = MagicMock()
        svc = BatchProcessingService(session, config)
        job = _make_job(session)

        with patch('src.plugins.translate._batch_proc.insert_batch_to_target',
                   new=AsyncMock(return_value=None)) as mock_insert:
            await svc.insert_batch_to_target(job, "batch-1", run_id)
            mock_insert.assert_called_once_with(session, config, job, "batch-1", run_id)
# #endregion Test.BatchProcessingService.Extra
