"""
Autodoc content caching mixin for BuildCache.

RFC: rfc-build-performance-optimizations Phase 3
Caches parsed autodoc module information to avoid re-parsing AST on every build.

This mixin caches the actual parsed module data (complementing AutodocTracker
which handles source→page dependency mapping). This enables skipping AST parsing
for unchanged Python source files.

Key Concepts:
- Content hash keying: Cache entries keyed by source file path + content hash
- Conservative invalidation: Only invalidate when source hash changes
- Thread-safe: Cache is read-only during parallel extraction

Related Modules:
- bengal.cache.build_cache.autodoc_tracking: Source→page dependency tracking
- bengal.autodoc.extractors.python.extractor: Python AST extraction
- bengal.utils.hashing: Shared hashing utilities

See Also:
- plan/rfc-build-performance-optimizations.md: Performance optimization RFC
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any

from bengal.utils.observability.logger import get_logger

logger = get_logger(__name__)


@dataclass
class CachedModuleInfo:
    """Cached parsed module data.

    Contains all information extracted from a Python module's AST,
    allowing us to skip AST parsing on subsequent builds if the source
    file hasn't changed.

    RFC: rfc-build-performance-optimizations Phase 3
    Stores the full DocElement serialization to enable complete reconstruction
    without AST parsing.

    Attributes:
        source_hash: Content hash of the source file (for validation)
        module_element_dict: Full DocElement serialization (from to_dict())
                          This allows complete reconstruction without AST parsing
    """

    source_hash: str
    module_element_dict: dict[str, Any]  # Full DocElement.to_dict() serialization


class AutodocContentCacheMixin:
    """
    Cache parsed autodoc content between builds.

    RFC: rfc-build-performance-optimizations Phase 3
    Caches parsed module information, enabling AST parsing to be skipped
    for unchanged source files.

    This mixin expects to be used with BuildCache which already has
    AutodocTracker for dependency tracking (via composition).
    """

    # Cache: source_file_path → CachedModuleInfo
    autodoc_content_cache: dict[str, CachedModuleInfo] = field(default_factory=dict)

    def get_cached_module(
        self,
        source_path: str,
        source_hash: str,
    ) -> CachedModuleInfo | None:
        """
        Return cached module info if hash matches.

        Args:
            source_path: Path to Python source file
            source_hash: Current content hash of source file

        Returns:
            CachedModuleInfo if cache hit (hash matches), None otherwise
        """
        cached = self.autodoc_content_cache.get(source_path)
        if cached and cached.source_hash == source_hash:
            logger.debug(
                "autodoc_cache_hit",
                source_path=source_path,
                hash=source_hash[:8],
            )
            return cached

        if cached:
            logger.debug(
                "autodoc_cache_miss_hash_mismatch",
                source_path=source_path,
                cached_hash=cached.source_hash[:8],
                current_hash=source_hash[:8],
            )

        return None

    def cache_module(
        self,
        source_path: str,
        info: CachedModuleInfo,
    ) -> None:
        """
        Cache parsed module info.

        Args:
            source_path: Path to Python source file
            info: CachedModuleInfo with parsed module data
        """
        self.autodoc_content_cache[source_path] = info
        # Extract child count from serialized element for logging
        children_count = len(info.module_element_dict.get("children", []))
        logger.debug(
            "autodoc_module_cached",
            source_path=source_path,
            hash=info.source_hash[:8],
            children=children_count,
        )

    def clear_autodoc_content_cache(self) -> None:
        """Clear all cached autodoc content."""
        count = len(self.autodoc_content_cache)
        self.autodoc_content_cache.clear()
        logger.debug("autodoc_content_cache_cleared", count=count)
