"""Tests for PDFExporter (refactored version)."""

import pytest
from unittest.mock import patch, MagicMock

from local_deep_research.web.services.pdf_service import weasyprint_available

# Skip all tests that need real PDF generation when WeasyPrint is unavailable
needs_weasyprint = pytest.mark.skipif(
    not weasyprint_available(),
    reason="WeasyPrint system libraries not available",
)


class TestPDFExporterProperties:
    """Tests for PDFExporter properties."""

    def test_format_name_is_pdf(self):
        """Test that format_name is 'pdf'."""
        from local_deep_research.exporters.pdf_exporter import PDFExporter

        exporter = PDFExporter()

        assert exporter.format_name == "pdf"

    def test_file_extension_is_pdf(self):
        """Test that file_extension is '.pdf'."""
        from local_deep_research.exporters.pdf_exporter import PDFExporter

        exporter = PDFExporter()

        assert exporter.file_extension == ".pdf"

    def test_mimetype_is_correct(self):
        """Test that mimetype is correct for PDF."""
        from local_deep_research.exporters.pdf_exporter import PDFExporter

        exporter = PDFExporter()

        assert exporter.mimetype == "application/pdf"


class TestPDFExporterExport:
    """Tests for PDFExporter.export method."""

    @pytest.fixture
    def exporter(self):
        """Create PDFExporter instance."""
        from local_deep_research.exporters.pdf_exporter import PDFExporter

        return PDFExporter()

    @needs_weasyprint
    def test_returns_export_result(self, exporter, simple_markdown):
        """Test that export returns ExportResult."""
        from local_deep_research.exporters import ExportResult

        result = exporter.export(simple_markdown)

        assert isinstance(result, ExportResult)

    @needs_weasyprint
    def test_result_content_is_bytes(self, exporter, simple_markdown):
        """Test that result content is bytes."""
        result = exporter.export(simple_markdown)

        assert isinstance(result.content, bytes)

    @needs_weasyprint
    def test_result_is_valid_pdf(self, exporter, simple_markdown):
        """Test that result is a valid PDF (starts with %PDF)."""
        result = exporter.export(simple_markdown)

        assert result.content.startswith(b"%PDF")

    @needs_weasyprint
    def test_result_has_reasonable_size(self, exporter, simple_markdown):
        """Test that generated PDF has a reasonable size."""
        result = exporter.export(simple_markdown)

        # A simple PDF should be at least a few KB
        assert len(result.content) > 1000

    @needs_weasyprint
    def test_result_filename_uses_title(self, exporter, simple_markdown):
        """Test that filename uses provided title."""
        from local_deep_research.exporters import ExportOptions

        options = ExportOptions(title="My Research Report")
        result = exporter.export(simple_markdown, options)

        assert "My_Research_Report" in result.filename
        assert result.filename.endswith(".pdf")

    @needs_weasyprint
    def test_result_filename_default_when_no_title(
        self, exporter, simple_markdown
    ):
        """Test that filename uses default when no title."""
        result = exporter.export(simple_markdown)

        assert "research_report" in result.filename
        assert result.filename.endswith(".pdf")

    @needs_weasyprint
    def test_result_mimetype_is_correct(self, exporter, simple_markdown):
        """Test that result mimetype is correct."""
        result = exporter.export(simple_markdown)

        assert result.mimetype == "application/pdf"

    @needs_weasyprint
    def test_handles_empty_markdown(self, exporter):
        """Test handling of empty markdown."""
        result = exporter.export("")

        assert result.content.startswith(b"%PDF")

    @needs_weasyprint
    def test_handles_markdown_with_all_features(
        self, exporter, sample_markdown
    ):
        """Test handling of markdown with tables, code, lists."""
        result = exporter.export(sample_markdown)

        assert result.content.startswith(b"%PDF")

    @needs_weasyprint
    def test_handles_special_characters(
        self, exporter, markdown_with_special_chars
    ):
        """Test handling of special characters."""
        result = exporter.export(markdown_with_special_chars)

        assert result.content.startswith(b"%PDF")

    @needs_weasyprint
    def test_handles_large_markdown(self, exporter):
        """Test handling of large markdown content."""
        large_content = "# Large Document\n\n"
        large_content += ("This is a paragraph. " * 100 + "\n\n") * 50

        result = exporter.export(large_content)

        assert result.content.startswith(b"%PDF")
        # Large content should produce larger PDF
        assert len(result.content) > 10000

    @needs_weasyprint
    def test_applies_custom_css(self, exporter, simple_markdown):
        """Test that custom CSS can be applied."""
        from local_deep_research.exporters import ExportOptions

        custom_css = "body { font-family: serif; }"
        options = ExportOptions(custom_options={"custom_css": custom_css})
        result = exporter.export(simple_markdown, options)

        assert result.content.startswith(b"%PDF")

    @needs_weasyprint
    def test_logs_pdf_size(self, exporter, simple_markdown):
        """Test that PDF size is logged."""
        with patch(
            "local_deep_research.exporters.pdf_exporter.logger"
        ) as mock_logger:
            exporter.export(simple_markdown)

            mock_logger.info.assert_called_once()
            call_args = mock_logger.info.call_args[0][0]
            assert "Generated PDF" in call_args
            assert "bytes" in call_args


class TestPDFExporterIntegration:
    """Integration tests for PDFExporter with ExporterRegistry."""

    def test_registered_in_registry(self):
        """Test that PDFExporter is registered in the registry."""
        from local_deep_research.exporters import ExporterRegistry

        assert ExporterRegistry.is_format_supported("pdf")

    def test_can_get_from_registry(self):
        """Test that PDFExporter can be retrieved from registry."""
        from local_deep_research.exporters import ExporterRegistry
        from local_deep_research.exporters.pdf_exporter import PDFExporter

        exporter = ExporterRegistry.get_exporter("pdf")

        assert isinstance(exporter, PDFExporter)

    @needs_weasyprint
    def test_export_via_registry(self, simple_markdown):
        """Test export via registry lookup."""
        from local_deep_research.exporters import ExporterRegistry

        exporter = ExporterRegistry.get_exporter("pdf")
        result = exporter.export(simple_markdown)

        assert result.content.startswith(b"%PDF")
        assert result.filename.endswith(".pdf")


class TestPDFExporterContentSizeLimit:
    """Tests for content size limit enforcement."""

    @pytest.fixture
    def exporter(self):
        """Create PDFExporter instance."""
        from local_deep_research.exporters.pdf_exporter import PDFExporter

        return PDFExporter()

    def test_raises_error_for_oversized_content(self, exporter):
        """Test that ValueError is raised for content exceeding size limit."""
        from local_deep_research.exporters.base import BaseExporter

        MAX_CONTENT_SIZE = BaseExporter.MAX_CONTENT_SIZE

        # Create content that exceeds the limit
        oversized_content = "x" * (MAX_CONTENT_SIZE + 1)

        with pytest.raises(ValueError) as exc_info:
            exporter.export(oversized_content)

        assert "exceeds maximum size" in str(exc_info.value)

    @needs_weasyprint
    def test_accepts_content_at_limit(self, exporter):
        """Test that content at exactly the limit is accepted."""
        from local_deep_research.exporters.base import BaseExporter

        MAX_CONTENT_SIZE = BaseExporter.MAX_CONTENT_SIZE

        # Create content at exactly the limit
        content_at_limit = "x" * MAX_CONTENT_SIZE

        mock_service = MagicMock()
        mock_service.markdown_to_pdf.return_value = b"%PDF-1.4 mock content"

        with patch(
            "local_deep_research.exporters.pdf_exporter.get_pdf_service",
            return_value=mock_service,
        ):
            result = exporter.export(content_at_limit)
            assert result.content.startswith(b"%PDF")

    @needs_weasyprint
    def test_accepts_content_under_limit(self, exporter, simple_markdown):
        """Test that content under the limit is accepted."""
        result = exporter.export(simple_markdown)

        assert result.content.startswith(b"%PDF")


class TestPDFExporterErrorHandling:
    """Tests for error handling in PDFExporter."""

    @pytest.fixture
    def exporter(self):
        """Create PDFExporter instance."""
        from local_deep_research.exporters.pdf_exporter import PDFExporter

        return PDFExporter()

    def test_logs_exception_on_error(self, exporter):
        """Test that exceptions are logged."""
        mock_service = MagicMock()
        mock_service.markdown_to_pdf.side_effect = Exception("Test error")

        with patch(
            "local_deep_research.exporters.pdf_exporter.get_pdf_service",
            return_value=mock_service,
        ):
            with patch(
                "local_deep_research.exporters.pdf_exporter.logger"
            ) as mock_logger:
                with pytest.raises(Exception):
                    exporter.export("test")

                mock_logger.exception.assert_called_once()

    def test_raises_runtime_error_when_weasyprint_missing(self, exporter):
        """Test that a helpful RuntimeError is raised when WeasyPrint is unavailable."""
        with patch(
            "local_deep_research.exporters.pdf_exporter.get_pdf_service",
            side_effect=RuntimeError("PDF export requires WeasyPrint"),
        ):
            with pytest.raises(RuntimeError, match="PDF export requires"):
                exporter.export("test")


class TestPDFExporterFilenameTruncation:
    """Tests for filename truncation with long titles."""

    @pytest.fixture
    def exporter(self):
        """Create PDFExporter instance."""
        from local_deep_research.exporters.pdf_exporter import PDFExporter

        return PDFExporter()

    @needs_weasyprint
    def test_filename_truncated_to_50_chars(self, exporter, simple_markdown):
        """Test that filename is truncated when title exceeds 50 chars."""
        from local_deep_research.exporters import ExportOptions

        # Title with more than 50 characters
        long_title = "A" * 60
        options = ExportOptions(title=long_title)
        result = exporter.export(simple_markdown, options)

        # Filename should be truncated to 50 chars + extension
        filename_without_ext = result.filename.rsplit(".", 1)[0]
        assert len(filename_without_ext) == 50
        assert result.filename.endswith(".pdf")

    @needs_weasyprint
    def test_filename_not_truncated_under_50_chars(
        self, exporter, simple_markdown
    ):
        """Test that filename is not truncated when under 50 chars."""
        from local_deep_research.exporters import ExportOptions

        title = "Short Title"
        options = ExportOptions(title=title)
        result = exporter.export(simple_markdown, options)

        assert "Short_Title" in result.filename
        assert result.filename.endswith(".pdf")
