"""Tests for transcription.services.transcription."""

from pathlib import Path

import pytest

from transcription.config import Settings
from transcription.providers.base import ProviderError, TranscriptionResult
from transcription.services.transcription import (
    PromptLoadError,
    TranscriptionError,
    load_image_payload,
    load_prompt_text,
    transcribe_document_image,
)


class _FakeProvider:
    def __init__(self, *, result: TranscriptionResult | None = None, error: Exception | None = None):
        self._result = result or TranscriptionResult(
            text="Transcript output",
            provider="openrouter",
            model="test-model",
        )
        self._error = error
        self.calls: list[dict[str, object]] = []

    def transcribe(self, *, prompt_text: str, image_bytes: bytes, mime_type: str) -> TranscriptionResult:
        self.calls.append(
            {
                "prompt_text": prompt_text,
                "image_bytes": image_bytes,
                "mime_type": mime_type,
            }
        )
        if self._error:
            raise self._error
        return self._result


@pytest.mark.unit
class TestPromptLoading:
    """Verify prompt artifact loading and validation."""

    def test_loads_prompt_text_from_prompt_dir(self, tmp_path: Path):
        """Prompt loader returns canonical prompt text from configured prompt directory."""
        prompt_dir = tmp_path / "prompts"
        prompt_dir.mkdir()
        prompt_file = prompt_dir / "transcribe_document.md"
        prompt_file.write_text("Prompt body", encoding="utf-8")

        settings = Settings(openrouter_api_key="test-key", prompt_dir=prompt_dir)
        text = load_prompt_text(settings=settings)

        assert text == "Prompt body"

    def test_missing_prompt_raises_error(self, tmp_path: Path):
        """Prompt loader raises PromptLoadError when the file is missing."""
        prompt_dir = tmp_path / "prompts"
        prompt_dir.mkdir()

        settings = Settings(openrouter_api_key="test-key", prompt_dir=prompt_dir)
        with pytest.raises(PromptLoadError) as exc_info:
            load_prompt_text(settings=settings)

        assert exc_info.value.category.value == "infrastructure_persistent_error"
        assert "verify prompt_dir" in exc_info.value.suggestion.lower()


@pytest.mark.unit
class TestImageLoading:
    """Verify local image payload loading and mime detection."""

    def test_load_image_payload_reads_bytes_and_mime_type(self, tmp_path: Path):
        """Image loader returns file bytes and a detected MIME type for supported files."""
        image_path = tmp_path / "sample.png"
        image_bytes = b"\x89PNG\r\n\x1a\n"
        image_path.write_bytes(image_bytes)

        loaded_bytes, mime_type = load_image_payload(image_path)

        assert loaded_bytes == image_bytes
        assert mime_type == "image/png"

    def test_missing_image_raises_error(self, tmp_path: Path):
        """Image loader raises TranscriptionError when image file does not exist."""
        missing = tmp_path / "missing.png"

        with pytest.raises(TranscriptionError) as exc_info:
            load_image_payload(missing)

        assert exc_info.value.category.value == "not_found_error"
        assert "verify" in exc_info.value.suggestion.lower()


@pytest.mark.unit
class TestTranscriptionService:
    """Verify service orchestration across prompt, image, and provider calls."""

    def test_transcribe_document_image_calls_provider_once(self, tmp_path: Path):
        """Service loads prompt and image, then invokes provider exactly once."""
        prompt_dir = tmp_path / "prompts"
        prompt_dir.mkdir()
        (prompt_dir / "transcribe_document.md").write_text("Prompt body", encoding="utf-8")

        image_path = tmp_path / "document.jpg"
        image_path.write_bytes(b"jpeg-bytes")

        settings = Settings(openrouter_api_key="test-key", prompt_dir=prompt_dir)
        provider = _FakeProvider()

        result = transcribe_document_image(image_path, settings=settings, provider=provider)

        assert result.text == "Transcript output"
        assert len(provider.calls) == 1
        assert provider.calls[0]["prompt_text"] == "Prompt body"
        assert provider.calls[0]["image_bytes"] == b"jpeg-bytes"
        assert provider.calls[0]["mime_type"] == "image/jpeg"

    def test_provider_error_is_wrapped(self, tmp_path: Path):
        """Service wraps provider failures in TranscriptionError."""
        prompt_dir = tmp_path / "prompts"
        prompt_dir.mkdir()
        (prompt_dir / "transcribe_document.md").write_text("Prompt body", encoding="utf-8")

        image_path = tmp_path / "document.png"
        image_path.write_bytes(b"png-bytes")

        settings = Settings(openrouter_api_key="test-key", prompt_dir=prompt_dir)
        provider = _FakeProvider(error=ProviderError("upstream failure"))

        with pytest.raises(TranscriptionError) as exc_info:
            transcribe_document_image(image_path, settings=settings, provider=provider)

        assert exc_info.value.category.value == "external_provider_error"
        assert exc_info.value.retriable is True
        assert "retry" in exc_info.value.suggestion.lower()
