"""Tests for the sources page routes and Source model properties."""

from pathlib import Path

import pytest
from sqlmodel import select
from sqlmodel.ext.asyncio.session import AsyncSession

from transcription.db import session_scope
from transcription.db.models import Document, Job, JobSourceStatus, JobStatus, Source


# --- Unit Tests for Model @property Definitions ---


class TestSourceModelProperties:
    """Direct unit tests for Source computed properties."""

    @pytest.mark.asyncio
    async def test_source_properties_with_no_job_sources(self):
        source = Source(
            page_number=1,
            upload_name="page_one.png",
            filename="stored_page_one.png",
            file_path="/tmp/stored_page_one.png",
        )

        assert source.latest_job_source is None
        assert source.latest_status is None
        assert source.latest_error_detail is None
        assert source.document_name is None

    @pytest.mark.asyncio
    async def test_source_properties_with_document_and_job_sources(self, seed_job):
        job_id = await seed_job(
            filename="source_prop_test.png",
            status=JobStatus.FAILED,
            transcription_text=None,
            error_detail="Timeout during OCR parsing",
        )

        async with session_scope() as session:
            job = await session.get(Job, job_id)
            assert job is not None
            source = (
                await session.exec(select(Source).where(Source.document_id == job.document_id))
            ).first()
            assert source is not None

            # Validate computed properties
            assert source.document_name is not None
            assert source.latest_status == JobSourceStatus.FAILED
            assert source.latest_error_detail == "Timeout during OCR parsing"
            assert source.latest_job_source is not None


# --- Integration Tests for Page Rendering ---


@pytest.mark.integration
class TestSourcesPageRendering:
    """Verify source list and detail routes render expected states."""

    def test_sources_page_renders_empty_state(self, app_client):
        _, client = app_client

        response = client.get("/ui/sources")

        assert response.status_code == 200
        assert "Source Asset Records" in response.text
        assert "No Source Assets Found".upper() in response.text.upper()
        assert "No source asset records found in repository." in response.text
        assert "Upload New Documents" not in response.text

    @pytest.mark.asyncio
    async def test_sources_page_lists_seeded_sources(self, app_client):
        _, client = app_client

        async with session_scope() as session:
            document = Document(name="Source Document", document_type="letter")
            session.add(document)
            await session.flush()
            session.add(
                Source(
                    document_id=document.id,
                    page_number=1,
                    upload_name="page_one.png",
                    filename="stored_page_one.png",
                    file_path="/tmp/stored_page_one.png",
                )
            )
            await session.commit()

        response = client.get("/ui/sources")

        assert response.status_code == 200
        assert "page_one.png" in response.text
        assert "Source Document" in response.text

    @pytest.mark.asyncio
    async def test_sources_page_filters_to_document_context(self, app_client):
        _, client = app_client

        async with session_scope() as session:
            target = Document(name="Target", document_type="letter")
            other = Document(name="Other", document_type="record")
            session.add_all([target, other])
            await session.flush()

            session.add_all(
                [
                    Source(
                        document_id=target.id,
                        page_number=1,
                        upload_name="target_page.png",
                        filename="target_stored.png",
                        file_path="/tmp/target_stored.png",
                    ),
                    Source(
                        document_id=other.id,
                        page_number=1,
                        upload_name="other_page.png",
                        filename="other_stored.png",
                        file_path="/tmp/other_stored.png",
                    ),
                ]
            )
            await session.commit()
            target_id = str(target.id)

        response = client.get(f"/ui/sources?document_id={target_id}")

        assert response.status_code == 200
        assert "Sources for Document" in response.text
        assert "target_page.png" in response.text
        assert "other_page.png" not in response.text

    @pytest.mark.asyncio
    async def test_sources_page_filters_to_job_context(self, app_client, seed_job):
        _, client = app_client
        job_id = await seed_job(filename="job-page.png", transcription_text="job text")

        response = client.get(f"/ui/sources?job_id={job_id}")

        assert response.status_code == 200
        assert "Sources for Job" in response.text
        assert "job-page.png" in response.text

    @pytest.mark.asyncio
    async def test_sources_page_job_context_shows_job_source_status_and_error_detail(
        self, app_client, seed_job
    ):
        _, client = app_client
        job_id = await seed_job(
            filename="job-failed-page.png",
            status=JobStatus.FAILED,
            transcription_text=None,
            error_detail="Provider timed out",
        )

        response = client.get(f"/ui/sources?job_id={job_id}")

        assert response.status_code == 200
        assert "job-failed-page.png" in response.text
        assert "failed" in response.text.lower()
        assert "Provider timed out" in response.text

    @pytest.mark.asyncio
    async def test_source_detail_page_renders_preview_and_revision_box(
        self, app_client, seed_job
    ):
        _, client = app_client
        fixture_path = (
            Path(__file__).resolve().parents[1]
            / "fixtures"
            / "images"
            / "valid"
            / "small_png.png"
        )
        job_id = await seed_job(
            filename="detail-source.png",
            transcription_text="original transcription text",
            revision_text="human revision text",
            source_file=fixture_path,
        )

        async with session_scope() as session:
            job = await session.get(Job, job_id)
            assert job is not None
            source = (
                await session.exec(select(Source).where(Source.document_id == job.document_id))
            ).first()
            assert source is not None
            source_id = str(source.id)

        response = client.get(f"/ui/sources/{source_id}")

        assert response.status_code == 200
        assert "SOURCE RECORD:" in response.text.upper()
        assert source_id.upper() in response.text.upper()
        assert "SOURCE PREVIEW" in response.text.upper()

    @pytest.mark.asyncio
    async def test_source_delete_page_blocks_when_source_is_job_linked(
        self, app_client, seed_job
    ):
        _, client = app_client
        job_id = await seed_job(filename="linked-source.png", transcription_text="linked text")

        async with session_scope() as session:
            job = await session.get(Job, job_id)
            assert job is not None
            source = (
                await session.exec(select(Source).where(Source.document_id == job.document_id))
            ).first()
            assert source is not None
            source_id = str(source.id)

        response = client.get(f"/ui/sources/{source_id}/delete")

        assert response.status_code == 200
        assert "Delete Source Confirmation".upper() in response.text.upper()
        assert "Cannot delete source linked to active jobs." in response.text

    @pytest.mark.asyncio
    async def test_source_delete_page_allows_unlinked_source(self, app_client):
        _, client = app_client

        async with session_scope() as session:
            document = Document(name="Unlinked Source Doc", document_type="memo")
            session.add(document)
            await session.flush()
            source = Source(
                document_id=document.id,
                page_number=1,
                upload_name="orphan-source.png",
                filename="orphan-source.png",
                file_path="/tmp/orphan-source.png",
            )
            session.add(source)
            await session.commit()
            source_id = str(source.id)

        response = client.get(f"/ui/sources/{source_id}/delete")

        assert response.status_code == 200
        assert "Delete Source Confirmation".upper() in response.text.upper()
        assert f"Are you sure you want to delete source {source_id}?" in response.text
        assert "Cannot delete source linked to active jobs." not in response.text
