"""
Tests for the content-type-aware chunking service.
"""

from unittest.mock import MagicMock, patch

from django.test import TestCase

from library.services.chunker import ChunkResult, ContentTypeChunker
from library.services.parsers import ParseResult, TextBlock


class ChunkResultTests(TestCase):
    """Tests for ChunkResult dataclass."""

    def test_len(self):
        result = ChunkResult(chunks=["a", "b", "c"], chunk_page_map={}, strategy="test")
        self.assertEqual(len(result), 3)

    def test_empty(self):
        result = ChunkResult(chunks=[], chunk_page_map={}, strategy="test")
        self.assertEqual(len(result), 0)


class ContentTypeChunkerTests(TestCase):
    """Tests for ContentTypeChunker."""

    def _make_parse_result(self, text: str, pages: int = 1) -> ParseResult:
        """Helper to create a ParseResult with text blocks."""
        blocks = []
        if pages == 1:
            blocks = [TextBlock(text=text, page=0)]
        else:
            chunk_size = len(text) // pages
            for i in range(pages):
                start = i * chunk_size
                end = start + chunk_size if i < pages - 1 else len(text)
                blocks.append(TextBlock(text=text[start:end], page=i))
        return ParseResult(text_blocks=blocks, images=[], metadata={}, file_type="txt")

    @patch("library.services.chunker.ContentTypeChunker._get_splitter")
    def test_chunk_dispatches_strategy(self, mock_splitter):
        """Chunker uses the strategy from config."""
        mock_instance = MagicMock()
        mock_instance.chunks.return_value = ["chunk1", "chunk2"]
        mock_splitter.return_value = mock_instance

        chunker = ContentTypeChunker()
        parse_result = self._make_parse_result("Some text to chunk into pieces")
        config = {"strategy": "chapter_aware", "chunk_size": 512, "chunk_overlap": 64}

        result = chunker.chunk(parse_result, config, library_type="fiction")

        self.assertIsInstance(result, ChunkResult)
        self.assertEqual(result.strategy, "chapter_aware")
        self.assertEqual(len(result.chunks), 2)
        mock_splitter.assert_called_once_with(512, 64)

    @patch("library.services.chunker.ContentTypeChunker._get_splitter")
    def test_empty_text_returns_empty(self, mock_splitter):
        """Empty text produces no chunks."""
        chunker = ContentTypeChunker()
        parse_result = ParseResult(text_blocks=[], images=[], metadata={}, file_type="txt")
        config = {"strategy": "section_aware", "chunk_size": 512, "chunk_overlap": 64}

        result = chunker.chunk(parse_result, config)

        self.assertEqual(len(result), 0)
        mock_splitter.assert_not_called()

    @patch("library.services.chunker.ContentTypeChunker._get_splitter")
    def test_default_config_values(self, mock_splitter):
        """Missing config keys use defaults."""
        mock_instance = MagicMock()
        mock_instance.chunks.return_value = ["chunk"]
        mock_splitter.return_value = mock_instance

        chunker = ContentTypeChunker()
        parse_result = self._make_parse_result("Text")

        result = chunker.chunk(parse_result, {})

        # Default: strategy=section_aware, chunk_size=512, overlap=64
        self.assertEqual(result.strategy, "section_aware")
        mock_splitter.assert_called_once_with(512, 64)

    @patch("library.services.chunker.ContentTypeChunker._get_splitter")
    def test_page_mapping(self, mock_splitter):
        """Chunks are mapped to their source pages."""
        mock_instance = MagicMock()
        mock_instance.chunks.return_value = ["Page 0 text", "Page 1 text"]
        mock_splitter.return_value = mock_instance

        chunker = ContentTypeChunker()
        parse_result = ParseResult(
            text_blocks=[
                TextBlock(text="Page 0 text content", page=0),
                TextBlock(text="Page 1 text content", page=1),
            ],
            images=[],
            metadata={},
            file_type="pdf",
        )
        config = {"strategy": "section_aware", "chunk_size": 512, "chunk_overlap": 64}

        result = chunker.chunk(parse_result, config)

        self.assertIn(0, result.chunk_page_map)
