"""
Unit tests for the highlight system.

Tests Highlight, HighlightColor, HighlightManager, and integration with query system.
"""

import unittest
import tempfile
import shutil
from pathlib import Path

from pyWebLayout.core.highlight import (
    Highlight,
    HighlightColor,
    HighlightManager,
    create_highlight_from_query_result
)
from pyWebLayout.core.query import QueryResult, SelectionRange


class TestHighlightColor(unittest.TestCase):
    """Test HighlightColor enum"""

    def test_colors_defined(self):
        """Test all expected colors are defined"""
        expected_colors = ['YELLOW', 'GREEN', 'BLUE', 'PINK', 'ORANGE', 'PURPLE', 'RED']

        for color_name in expected_colors:
            self.assertTrue(hasattr(HighlightColor, color_name))
            color = getattr(HighlightColor, color_name)
            self.assertIsInstance(color.value, tuple)
            self.assertEqual(len(color.value), 4)  # RGBA

    def test_yellow_is_default(self):
        """Test yellow highlight color"""
        yellow = HighlightColor.YELLOW.value
        self.assertEqual(yellow, (255, 255, 0, 100))


class TestHighlight(unittest.TestCase):
    """Test Highlight dataclass"""

    def test_init_basic(self):
        """Test basic Highlight creation"""
        highlight = Highlight(
            id="test-id",
            bounds=[(10, 20, 50, 15)],
            color=(255, 255, 0, 100),
            text="Hello"
        )

        self.assertEqual(highlight.id, "test-id")
        self.assertEqual(len(highlight.bounds), 1)
        self.assertEqual(highlight.bounds[0], (10, 20, 50, 15))
        self.assertEqual(highlight.color, (255, 255, 0, 100))
        self.assertEqual(highlight.text, "Hello")
        self.assertIsNone(highlight.note)
        self.assertEqual(highlight.tags, [])

    def test_init_with_metadata(self):
        """Test Highlight with full metadata"""
        highlight = Highlight(
            id="test-id",
            bounds=[(10, 20, 50, 15)],
            color=(255, 255, 0, 100),
            text="Hello",
            note="Important word",
            tags=["important", "keyword"],
            timestamp=1234567890.0,
            start_word_index=5,
            end_word_index=5
        )

        self.assertEqual(highlight.note, "Important word")
        self.assertEqual(highlight.tags, ["important", "keyword"])
        self.assertEqual(highlight.timestamp, 1234567890.0)
        self.assertEqual(highlight.start_word_index, 5)
        self.assertEqual(highlight.end_word_index, 5)

    def test_to_dict(self):
        """Test Highlight serialization"""
        highlight = Highlight(
            id="test-id",
            bounds=[(10, 20, 50, 15), (70, 20, 40, 15)],
            color=(255, 255, 0, 100),
            text="Hello world",
            note="Test note",
            tags=["test"],
            timestamp=1234567890.0
        )

        data = highlight.to_dict()

        self.assertEqual(data['id'], "test-id")
        self.assertEqual(len(data['bounds']), 2)
        self.assertEqual(data['bounds'][0], (10, 20, 50, 15))
        self.assertEqual(data['color'], (255, 255, 0, 100))
        self.assertEqual(data['text'], "Hello world")
        self.assertEqual(data['note'], "Test note")
        self.assertEqual(data['tags'], ["test"])
        self.assertEqual(data['timestamp'], 1234567890.0)

    def test_from_dict(self):
        """Test Highlight deserialization"""
        data = {
            'id': "test-id",
            'bounds': [[10, 20, 50, 15], [70, 20, 40, 15]],
            'color': [255, 255, 0, 100],
            'text': "Hello world",
            'note': "Test note",
            'tags': ["test"],
            'timestamp': 1234567890.0,
            'start_word_index': 5,
            'end_word_index': 6
        }

        highlight = Highlight.from_dict(data)

        self.assertEqual(highlight.id, "test-id")
        self.assertEqual(len(highlight.bounds), 2)
        self.assertEqual(highlight.bounds[0], (10, 20, 50, 15))
        self.assertEqual(highlight.color, (255, 255, 0, 100))
        self.assertEqual(highlight.text, "Hello world")
        self.assertEqual(highlight.note, "Test note")
        self.assertEqual(highlight.tags, ["test"])
        self.assertEqual(highlight.start_word_index, 5)
        self.assertEqual(highlight.end_word_index, 6)


class TestHighlightManager(unittest.TestCase):
    """Test HighlightManager class"""

    def setUp(self):
        """Create temporary directory for highlights"""
        self.temp_dir = tempfile.mkdtemp()
        self.manager = HighlightManager(
            document_id="test-doc",
            highlights_dir=self.temp_dir
        )

    def tearDown(self):
        """Clean up temporary directory"""
        shutil.rmtree(self.temp_dir)

    def test_init(self):
        """Test HighlightManager initialization"""
        self.assertEqual(self.manager.document_id, "test-doc")
        self.assertEqual(self.manager.highlights_dir, Path(self.temp_dir))
        self.assertEqual(len(self.manager.highlights), 0)

    def test_add_highlight(self):
        """Test adding a highlight"""
        highlight = Highlight(
            id="test-1",
            bounds=[(10, 20, 50, 15)],
            color=(255, 255, 0, 100),
            text="Test"
        )

        self.manager.add_highlight(highlight)

        self.assertEqual(len(self.manager.highlights), 1)
        self.assertIn("test-1", self.manager.highlights)
        self.assertEqual(self.manager.highlights["test-1"], highlight)

    def test_remove_highlight(self):
        """Test removing a highlight"""
        highlight = Highlight(
            id="test-1",
            bounds=[(10, 20, 50, 15)],
            color=(255, 255, 0, 100),
            text="Test"
        )

        self.manager.add_highlight(highlight)
        self.assertEqual(len(self.manager.highlights), 1)

        result = self.manager.remove_highlight("test-1")
        self.assertTrue(result)
        self.assertEqual(len(self.manager.highlights), 0)

    def test_remove_nonexistent_highlight(self):
        """Test removing a highlight that doesn't exist"""
        result = self.manager.remove_highlight("nonexistent")
        self.assertFalse(result)

    def test_get_highlight(self):
        """Test getting a highlight by ID"""
        highlight = Highlight(
            id="test-1",
            bounds=[(10, 20, 50, 15)],
            color=(255, 255, 0, 100),
            text="Test"
        )

        self.manager.add_highlight(highlight)
        retrieved = self.manager.get_highlight("test-1")

        self.assertIsNotNone(retrieved)
        self.assertEqual(retrieved.id, "test-1")
        self.assertEqual(retrieved.text, "Test")

    def test_list_highlights(self):
        """Test listing all highlights"""
        highlight1 = Highlight(
            id="test-1",
            bounds=[(10, 20, 50, 15)],
            color=(255, 255, 0, 100),
            text="First"
        )
        highlight2 = Highlight(
            id="test-2",
            bounds=[(100, 20, 50, 15)],
            color=(100, 255, 100, 100),
            text="Second"
        )

        self.manager.add_highlight(highlight1)
        self.manager.add_highlight(highlight2)

        highlights = self.manager.list_highlights()
        self.assertEqual(len(highlights), 2)
        self.assertIn(highlight1, highlights)
        self.assertIn(highlight2, highlights)

    def test_clear_all(self):
        """Test clearing all highlights"""
        highlight1 = Highlight(
            id="test-1",
            bounds=[(10, 20, 50, 15)],
            color=(255, 255, 0, 100),
            text="First"
        )
        highlight2 = Highlight(
            id="test-2",
            bounds=[(100, 20, 50, 15)],
            color=(100, 255, 100, 100),
            text="Second"
        )

        self.manager.add_highlight(highlight1)
        self.manager.add_highlight(highlight2)
        self.assertEqual(len(self.manager.highlights), 2)

        self.manager.clear_all()
        self.assertEqual(len(self.manager.highlights), 0)

    def test_persistence(self):
        """Test that highlights are persisted to disk"""
        highlight = Highlight(
            id="test-1",
            bounds=[(10, 20, 50, 15)],
            color=(255, 255, 0, 100),
            text="Persisted"
        )

        self.manager.add_highlight(highlight)

        # Create new manager for same document
        new_manager = HighlightManager(
            document_id="test-doc",
            highlights_dir=self.temp_dir
        )

        # Should load existing highlights
        self.assertEqual(len(new_manager.highlights), 1)
        self.assertIn("test-1", new_manager.highlights)
        self.assertEqual(new_manager.highlights["test-1"].text, "Persisted")

    def test_get_highlights_for_page(self):
        """Test filtering highlights by page bounds"""
        # Highlight on page
        highlight1 = Highlight(
            id="test-1",
            bounds=[(100, 100, 50, 15)],
            color=(255, 255, 0, 100),
            text="On page"
        )

        # Highlight off page
        highlight2 = Highlight(
            id="test-2",
            bounds=[(1000, 1000, 50, 15)],
            color=(255, 255, 0, 100),
            text="Off page"
        )

        self.manager.add_highlight(highlight1)
        self.manager.add_highlight(highlight2)

        # Page bounds (0, 0, 800, 1000)
        page_bounds = (0, 0, 800, 1000)
        page_highlights = self.manager.get_highlights_for_page(page_bounds)

        self.assertEqual(len(page_highlights), 1)
        self.assertEqual(page_highlights[0].id, "test-1")


class TestCreateHighlightFromQueryResult(unittest.TestCase):
    """Test create_highlight_from_query_result function"""

    def test_create_from_single_result(self):
        """Test creating highlight from single QueryResult"""
        result = QueryResult(
            object=object(),
            object_type="text",
            bounds=(10, 20, 50, 15),
            text="Hello"
        )

        highlight = create_highlight_from_query_result(
            result,
            color=(255, 255, 0, 100),
            note="Test note",
            tags=["test"]
        )

        self.assertIsNotNone(highlight.id)
        self.assertEqual(len(highlight.bounds), 1)
        self.assertEqual(highlight.bounds[0], (10, 20, 50, 15))
        self.assertEqual(highlight.color, (255, 255, 0, 100))
        self.assertEqual(highlight.text, "Hello")
        self.assertEqual(highlight.note, "Test note")
        self.assertEqual(highlight.tags, ["test"])
        self.assertIsNotNone(highlight.timestamp)

    def test_create_from_selection_range(self):
        """Test creating highlight from SelectionRange"""
        results = [
            QueryResult(object(), "text", (10, 20, 30, 15), text="Hello"),
            QueryResult(object(), "text", (45, 20, 35, 15), text="world")
        ]

        sel_range = SelectionRange((10, 20), (80, 35), results)

        highlight = create_highlight_from_query_result(
            sel_range,
            color=(100, 255, 100, 100),
            note="Multi-word"
        )

        self.assertIsNotNone(highlight.id)
        self.assertEqual(len(highlight.bounds), 2)
        self.assertEqual(highlight.bounds[0], (10, 20, 30, 15))
        self.assertEqual(highlight.bounds[1], (45, 20, 35, 15))
        self.assertEqual(highlight.color, (100, 255, 100, 100))
        self.assertEqual(highlight.text, "Hello world")
        self.assertEqual(highlight.note, "Multi-word")


if __name__ == '__main__':
    unittest.main()
