"""Tests for transcription.models — Document, Job, Transcript persistence and relationships."""

from uuid import UUID

import pytest
from sqlalchemy.exc import IntegrityError

from transcription.models import Document
from transcription.models import Job
from transcription.models import JobStatus
from transcription.models import Transcript


def _make_document(**overrides) -> Document:
    """Create a Document with sensible defaults."""
    defaults = {"filename": "letter.jpg", "file_path": "/uploads/letter.jpg"}
    defaults.update(overrides)
    return Document(**defaults)


def _persist_document(session) -> Document:
    """Create, persist, and return a Document."""
    doc = _make_document()
    session.add(doc)
    session.commit()
    session.refresh(doc)
    return doc


def _persist_job(session, document: Document) -> Job:
    """Create, persist, and return a Job linked to a Document."""
    job = Job(document_id=document.id)
    session.add(job)
    session.commit()
    session.refresh(job)
    return job


class TestDocumentModel:
    """Verify Document creation and default field population."""

    def test_can_be_persisted(self, session):
        """A Document round-trips through the database with correct fields."""
        doc = _persist_document(session)
        fetched = session.get(Document, doc.id)
        assert fetched is not None
        assert fetched.filename == "letter.jpg"
        assert fetched.file_path == "/uploads/letter.jpg"

    def test_defaults_are_populated(self, session):
        """id is a UUID and uploaded_at is populated on creation."""
        doc = _persist_document(session)
        assert isinstance(doc.id, UUID)
        assert doc.uploaded_at is not None


class TestJobModel:
    """Verify Job creation, defaults, and status transitions."""

    def test_can_be_created_for_document(self, session):
        """A Job linked to a Document via FK persists correctly."""
        doc = _persist_document(session)
        job = _persist_job(session, doc)
        fetched = session.get(Job, job.id)
        assert fetched is not None
        assert fetched.document_id == doc.id

    def test_defaults_are_populated(self, session):
        """Default status is queued; created_at and updated_at are populated."""
        doc = _persist_document(session)
        job = _persist_job(session, doc)
        assert job.status == JobStatus.QUEUED
        assert job.retry_count == 0
        assert job.created_at is not None
        assert job.updated_at is not None

    def test_transitions_to_transcribed(self, session):
        """Status updates from queued to processing to transcribed."""
        doc = _persist_document(session)
        job = _persist_job(session, doc)
        assert job.status == JobStatus.QUEUED

        job.status = JobStatus.PROCESSING
        session.add(job)
        session.commit()
        session.refresh(job)
        assert job.status == JobStatus.PROCESSING

        job.status = JobStatus.TRANSCRIBED
        session.add(job)
        session.commit()
        session.refresh(job)
        assert job.status == JobStatus.TRANSCRIBED

    def test_transitions_to_failed(self, session):
        """Status updates from processing to failed."""
        doc = _persist_document(session)
        job = _persist_job(session, doc)

        job.status = JobStatus.PROCESSING
        session.add(job)
        session.commit()
        session.refresh(job)

        job.status = JobStatus.FAILED
        session.add(job)
        session.commit()
        session.refresh(job)
        assert job.status == JobStatus.FAILED


class TestTranscriptModel:
    """Verify Transcript persistence for success and failure cases."""

    def test_success_record_persists(self, session):
        """A Transcript with text set and error_detail None persists correctly."""
        doc = _persist_document(session)
        job = _persist_job(session, doc)
        transcript = Transcript(
            job_id=job.id,
            revision=0,
            provider="openrouter",
            model="google/gemini-2.5-flash",
            prompt_name="transcribe_document.md",
            text="Dear Sir, ...",
        )
        session.add(transcript)
        session.commit()
        session.refresh(transcript)

        fetched = session.get(Transcript, transcript.id)
        assert fetched is not None
        assert fetched.text == "Dear Sir, ..."
        assert fetched.error_detail is None

    def test_failure_record_persists(self, session):
        """A Transcript with text None and error_detail set persists correctly."""
        doc = _persist_document(session)
        job = _persist_job(session, doc)
        transcript = Transcript(
            job_id=job.id,
            revision=0,
            provider="openrouter",
            model="google/gemini-2.5-flash",
            prompt_name="transcribe_document.md",
            error_detail="Provider timeout",
        )
        session.add(transcript)
        session.commit()
        session.refresh(transcript)

        fetched = session.get(Transcript, transcript.id)
        assert fetched is not None
        assert fetched.text is None
        assert fetched.error_detail == "Provider timeout"

    def test_job_revision_pair_is_unique(self, session):
        """Duplicate job_id and revision combinations raise an integrity error."""
        doc = _persist_document(session)
        job = _persist_job(session, doc)

        session.add(
            Transcript(
                job_id=job.id,
                revision=0,
                provider="openrouter",
                model="google/gemini-2.5-flash",
                prompt_name="transcribe_document.md",
                text="First",
            )
        )
        session.add(
            Transcript(
                job_id=job.id,
                revision=1,
                provider="openrouter",
                model="google/gemini-2.5-flash",
                prompt_name="transcribe_document.md",
                text="Second",
            )
        )
        session.commit()

        session.add(
            Transcript(
                job_id=job.id,
                revision=1,
                provider="openrouter",
                model="google/gemini-2.5-flash",
                prompt_name="transcribe_document.md",
                text="Duplicate",
            )
        )
        with pytest.raises(IntegrityError):
            session.commit()
        session.rollback()


class TestRelationships:
    """Verify SQLModel relationship navigation between models."""

    def test_document_exposes_jobs(self, session):
        """document.jobs returns the linked Job list."""
        doc = _persist_document(session)
        _persist_job(session, doc)
        _persist_job(session, doc)

        session.refresh(doc)
        assert len(doc.jobs) == 2
        assert all(isinstance(j, Job) for j in doc.jobs)

    def test_job_exposes_transcripts(self, session):
        """job.transcripts returns linked Transcript history."""
        doc = _persist_document(session)
        job = _persist_job(session, doc)
        session.add(
            Transcript(
                job_id=job.id,
                revision=0,
                provider="openrouter",
                model="google/gemini-2.5-flash",
                prompt_name="transcribe_document.md",
                text="Transcribed text",
            )
        )
        session.add(
            Transcript(
                job_id=job.id,
                revision=1,
                provider="openrouter",
                model="google/gemini-2.5-flash",
                prompt_name="transcribe_document.md",
                text="Transcribed text v2",
            )
        )
        session.commit()

        session.refresh(job)
        assert len(job.transcripts) == 2
        assert all(isinstance(t, Transcript) for t in job.transcripts)
