import json
import logging
from typing import Dict, Any
from mini_videorag.core.pipeline import PipelineResult
from mini_videorag.core.formatters import get_formatter, load_all_formatters

logger = logging.getLogger(__name__)


class MetadataBuilder:
    """
    Build metadata from processor results using formatters.

    Uses processor formatters as single source of truth for metadata.
    """

    def __init__(self, pipeline_result: PipelineResult):
        """
        Initialize builder with pipeline results.

        Args:
            pipeline_result: PipelineResult from pipeline.run_all()
        """
        self.pipeline_result = pipeline_result
        load_all_formatters()

    def get_rag_metadata(self) -> Dict[str, Any]:
        """
        Extract structured metadata from all successful processors.

        Uses formatter.rag_metadata as single source of truth.
        Flattens complex types (list, dict) to strings for LanceDB compatibility.

        Flattening strategy:
        - Lists: CSV format (as per architecture docs)
        - Dicts: JSON string
        - Primitives: Keep as-is

        Returns:
            Dict with all processor metadata merged (LanceDB-compatible)
        """
        all_metadata = {}

        for name, result in self.pipeline_result.results.items():
            if not result.success:
                continue

            formatter = get_formatter(name)
            formatted = formatter(result)

            if formatted.rag_metadata:
                for key, value in formatted.rag_metadata.items():
                    if isinstance(value, list):
                        flattened = ",".join(str(v) for v in value)
                        all_metadata[key] = flattened
                        logger.debug(f"Flattened list metadata '{key}': {value} -> '{flattened}'")
                    elif isinstance(value, dict):
                        flattened = json.dumps(value)
                        all_metadata[key] = flattened
                        logger.debug(
                            f"Flattened dict metadata '{key}': {len(value)} keys -> JSON string"
                        )
                    else:
                        all_metadata[key] = value

        return all_metadata

    def build_context_summary(self) -> str:
        """
        Build VLM context by aggregating vlm_context from all processor formatters.

        Each processor defines its own context contribution via formatter.vlm_context.
        This is modular - adding new processors just requires updating their formatter.

        Returns:
            Formatted context text for VLM
        """
        context_parts = []

        for name, result in self.pipeline_result.results.items():
            if not result.success:
                continue

            formatter = get_formatter(name)
            formatted = formatter(result)

            if formatted.vlm_context:
                context_parts.append(formatted.vlm_context)

        return "\n".join(context_parts)

    def format_metadata_as_text(self, mode: str = "full") -> str:
        """
        Aggregate formatted text from all successful processors.

        Uses formatter outputs as single source of truth:
        - mode="full": Aggregates formatter.content_text (comprehensive)
        - mode="compact": Aggregates formatter.summary_line (one-line summaries)

        Args:
            mode: "full" for comprehensive, "compact" for search summary

        Returns:
            Formatted text string
        """
        parts = []

        for name, result in self.pipeline_result.results.items():
            if not result.success:
                continue

            formatter = get_formatter(name)
            formatted = formatter(result)

            if formatted.is_empty:
                continue

            if mode == "compact":
                parts.append(formatted.summary_line)
            else:  # full mode
                if formatted.content_text:
                    parts.append(formatted.content_text)

        separator = " | " if mode == "compact" else "\n\n"
        return separator.join(parts)
