"""
Text highlighting system for ebook reader.

Provides data structures and utilities for highlighting text regions,
managing highlight collections, and rendering highlights on pages.
"""

from __future__ import annotations
from dataclasses import dataclass
from typing import List, Tuple, Optional, Dict, Any
from enum import Enum
import json
from pathlib import Path


class HighlightColor(Enum):
    """Predefined highlight colors with RGBA values"""
    YELLOW = (255, 255, 0, 100)      # Classic highlight yellow
    GREEN = (100, 255, 100, 100)     # Green for verified/correct
    BLUE = (100, 200, 255, 100)      # Blue for important
    PINK = (255, 150, 200, 100)      # Pink for questions
    ORANGE = (255, 180, 100, 100)    # Orange for warnings
    PURPLE = (200, 150, 255, 100)    # Purple for definitions
    RED = (255, 100, 100, 100)       # Red for errors/concerns


@dataclass
class Highlight:
    """
    Represents a highlighted text region.

    Highlights are stored with both pixel bounds (for rendering) and
    semantic bounds (text content, for persistence across font changes).
    """
    # Identification
    id: str  # Unique identifier

    # Visual properties
    bounds: List[Tuple[int, int, int, int]]  # List of (x, y, w, h) rectangles
    color: Tuple[int, int, int, int]  # RGBA color

    # Semantic properties (for persistence)
    text: str  # The highlighted text
    start_word_index: Optional[int] = None  # Word index in document (if available)
    end_word_index: Optional[int] = None

    # Metadata
    note: Optional[str] = None  # Optional annotation
    tags: List[str] = None  # Optional categorization tags
    timestamp: Optional[float] = None  # When created

    def __post_init__(self):
        """Initialize default values"""
        if self.tags is None:
            self.tags = []

    def to_dict(self) -> Dict[str, Any]:
        """Serialize to dictionary"""
        return {
            'id': self.id,
            'bounds': self.bounds,
            'color': self.color,
            'text': self.text,
            'start_word_index': self.start_word_index,
            'end_word_index': self.end_word_index,
            'note': self.note,
            'tags': self.tags,
            'timestamp': self.timestamp
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'Highlight':
        """Deserialize from dictionary"""
        return cls(
            id=data['id'],
            bounds=[tuple(b) for b in data['bounds']],
            color=tuple(data['color']),
            text=data['text'],
            start_word_index=data.get('start_word_index'),
            end_word_index=data.get('end_word_index'),
            note=data.get('note'),
            tags=data.get('tags', []),
            timestamp=data.get('timestamp')
        )


class HighlightManager:
    """
    Manages highlights for a document.

    Handles adding, removing, listing, and persisting highlights.
    """

    def __init__(self, document_id: str, highlights_dir: str = "highlights"):
        """
        Initialize highlight manager.

        Args:
            document_id: Unique identifier for the document
            highlights_dir: Directory to store highlight data
        """
        self.document_id = document_id
        self.highlights_dir = Path(highlights_dir)
        self.highlights: Dict[str, Highlight] = {}  # id -> Highlight

        # Create directory if it doesn't exist
        self.highlights_dir.mkdir(parents=True, exist_ok=True)

        # Load existing highlights
        self._load_highlights()

    def add_highlight(self, highlight: Highlight) -> None:
        """
        Add a highlight.

        Args:
            highlight: Highlight to add
        """
        self.highlights[highlight.id] = highlight
        self._save_highlights()

    def remove_highlight(self, highlight_id: str) -> bool:
        """
        Remove a highlight by ID.

        Args:
            highlight_id: ID of highlight to remove

        Returns:
            True if removed, False if not found
        """
        if highlight_id in self.highlights:
            del self.highlights[highlight_id]
            self._save_highlights()
            return True
        return False

    def get_highlight(self, highlight_id: str) -> Optional[Highlight]:
        """Get a highlight by ID"""
        return self.highlights.get(highlight_id)

    def list_highlights(self) -> List[Highlight]:
        """Get all highlights"""
        return list(self.highlights.values())

    def clear_all(self) -> None:
        """Remove all highlights"""
        self.highlights.clear()
        self._save_highlights()

    def get_highlights_for_page(
            self, page_bounds: Tuple[int, int, int, int]) -> List[Highlight]:
        """
        Get highlights that appear on a specific page.

        Args:
            page_bounds: Page bounds (x, y, width, height)

        Returns:
            List of highlights on this page
        """
        page_x, page_y, page_w, page_h = page_bounds
        page_highlights = []

        for highlight in self.highlights.values():
            # Check if any highlight bounds overlap with page
            for hx, hy, hw, hh in highlight.bounds:
                if (hx < page_x + page_w and hx + hw > page_x and
                        hy < page_y + page_h and hy + hh > page_y):
                    page_highlights.append(highlight)
                    break

        return page_highlights

    def _get_filepath(self) -> Path:
        """Get filepath for this document's highlights"""
        return self.highlights_dir / f"{self.document_id}_highlights.json"

    def _save_highlights(self) -> None:
        """Persist highlights to disk"""
        try:
            filepath = self._get_filepath()
            data = {
                'document_id': self.document_id,
                'highlights': [h.to_dict() for h in self.highlights.values()]
            }

            with open(filepath, 'w') as f:
                json.dump(data, f, indent=2)
        except Exception as e:
            print(f"Error saving highlights: {e}")

    def _load_highlights(self) -> None:
        """Load highlights from disk"""
        try:
            filepath = self._get_filepath()
            if not filepath.exists():
                return

            with open(filepath, 'r') as f:
                data = json.load(f)

            self.highlights = {
                h['id']: Highlight.from_dict(h)
                for h in data.get('highlights', [])
            }
        except Exception as e:
            print(f"Error loading highlights: {e}")
            self.highlights = {}


def create_highlight_from_query_result(
    result,
    color: Tuple[int, int, int, int] = HighlightColor.YELLOW.value,
    note: Optional[str] = None,
    tags: Optional[List[str]] = None
) -> Highlight:
    """
    Create a highlight from a QueryResult.

    Args:
        result: QueryResult from query_pixel or query_range
        color: RGBA color tuple
        note: Optional annotation
        tags: Optional categorization tags

    Returns:
        Highlight instance
    """
    from time import time
    import uuid

    # Handle single result or SelectionRange
    if hasattr(result, 'results'):  # SelectionRange
        bounds = result.bounds_list
        text = result.text
    else:  # Single QueryResult
        bounds = [result.bounds]
        text = result.text or ""

    return Highlight(
        id=str(uuid.uuid4()),
        bounds=bounds,
        color=color,
        text=text,
        note=note,
        tags=tags or [],
        timestamp=time()
    )
