"""
Public API for card_framework wrapper — symbols, search, DSL docs, and DSL parsing.

This module provides all the public-facing functions that consumers use.
It imports shared state from wrapper_setup via module reference to avoid
circular imports.

Usage:
    from gchat.wrapper_api import get_gchat_symbols, parse_dsl
"""

import logging
from typing import Any, Dict, List, Optional

import gchat.wrapper_setup as _setup
from config.enhanced_logging import setup_logger

logger = setup_logger(__name__)


# =============================================================================
# SYMBOL GENERATION
# =============================================================================


def get_gchat_symbols(force_regenerate: bool = False) -> Dict[str, str]:
    """
    Get the symbol table for gchat card components.

    Returns cached symbols, generating them on first call.
    Symbols are auto-generated by SymbolGenerator based on LETTER_SYMBOLS pools.

    Args:
        force_regenerate: If True, regenerate symbols even if cached

    Returns:
        Dict mapping component names to symbols (e.g., {"Button": "ᵬ"})
    """
    with _setup._symbols_lock:
        if _setup._symbols is None or force_regenerate:
            _setup._symbols = _generate_gchat_symbols()

    return _setup._symbols


def _generate_gchat_symbols() -> Dict[str, str]:
    """Load symbols from the ModuleWrapper (Single Source of Truth).

    The ModuleWrapper loads symbols from Qdrant and also includes custom
    Google Chat API components (Carousel, NestedWidget, CardFixedFooter, etc.)
    that were registered via register_custom_components().

    This function simply returns the wrapper's symbol_mapping, which is
    the authoritative source for all component symbols.
    """
    wrapper = _setup.get_card_framework_wrapper(ensure_text_indices=False)

    # The wrapper's symbol_mapping includes both:
    # 1. Symbols loaded from Qdrant (card_framework components)
    # 2. Custom Chat API symbols (registered via register_custom_components)
    symbols = wrapper.symbol_mapping or {}

    if symbols:
        logger.info(f"🔣 Loaded {len(symbols)} symbols from ModuleWrapper")
        return symbols

    # Fallback: Load from Qdrant directly if symbol_mapping is empty
    if wrapper.client:
        try:
            from qdrant_client import models

            # Scroll through ALL class components to get their stored symbols
            offset = None
            while True:
                results, offset = wrapper.client.scroll(
                    collection_name=wrapper.collection_name,
                    scroll_filter=models.Filter(
                        must=[
                            models.FieldCondition(
                                key="type",
                                match=models.MatchValue(value="class"),
                            )
                        ]
                    ),
                    limit=500,
                    offset=offset,
                    with_payload=["name", "symbol"],
                )

                for p in results:
                    name = p.payload.get("name")
                    symbol = p.payload.get("symbol")
                    if name and symbol:
                        symbols[name] = symbol

                if offset is None:
                    break

            if symbols:
                logger.info(f"🔣 Loaded {len(symbols)} symbols from Qdrant (fallback)")
                return symbols

        except Exception as e:
            logger.warning(f"Failed to load symbols from Qdrant: {e}")

    # Ultimate fallback: Generate symbols if Qdrant unavailable
    logger.warning("⚠️ Falling back to symbol generation (Qdrant unavailable)")
    from adapters.module_wrapper.symbol_generator import SymbolGenerator

    component_names = []
    if wrapper.components:
        component_names = [
            comp.name
            for comp in wrapper.components.values()
            if comp.component_type == "class"
        ]

    generator = SymbolGenerator(module_prefix=None)
    symbols = generator.generate_symbols(component_names)

    logger.info(f"✅ Generated {len(symbols)} symbols (fallback)")
    return symbols


def get_gchat_symbol_table_text() -> str:
    """
    Get a formatted symbol table for LLM instructions.

    Returns:
        Markdown-formatted symbol table
    """
    symbols = get_gchat_symbols()

    # Group by first letter
    from collections import defaultdict

    by_letter = defaultdict(list)
    for comp, sym in symbols.items():
        by_letter[comp[0].upper()].append((sym, comp))

    lines = ["## Google Chat Card Symbols\n"]
    for letter in sorted(by_letter.keys()):
        items = by_letter[letter]
        mappings = [f"{sym}={comp}" for sym, comp in sorted(items, key=lambda x: x[1])]
        lines.append(f"**{letter}:** {', '.join(mappings)}")

    return "\n".join(lines)


def configure_structure_dsl_symbols():
    """
    Configure the structure_dsl module with gchat symbols.

    This updates the global symbol tables in structure_dsl.py to use
    the gchat-specific symbols, enabling both natural language and
    symbol-based card descriptions.
    """
    import gchat.structure_dsl as structure_dsl_module
    from gchat.structure_dsl import (
        ALL_SYMBOLS,
        COMPONENT_TO_SYMBOL,
        SYMBOL_TO_COMPONENT,
    )

    symbols = get_gchat_symbols()

    # Update structure_dsl globals
    SYMBOL_TO_COMPONENT.clear()
    COMPONENT_TO_SYMBOL.clear()

    for comp, sym in symbols.items():
        SYMBOL_TO_COMPONENT[sym] = comp
        COMPONENT_TO_SYMBOL[comp] = sym

    ALL_SYMBOLS.clear()
    ALL_SYMBOLS.update(SYMBOL_TO_COMPONENT.keys())

    # Build ASCII confusable aliases (e.g. 'g' → 'ℊ')
    from gchat.structure_dsl import _build_ascii_confusables

    _build_ascii_confusables()

    # Mark as initialized
    structure_dsl_module._initialized = True

    logger.info(f"🔣 Configured structure_dsl with {len(symbols)} symbols")


# =============================================================================
# CONVENIENCE SEARCH FUNCTIONS
# =============================================================================


def search_components(
    query: str,
    limit: int = 10,
    search_mode: str = "hybrid",
) -> List[Dict]:
    """
    Search for card components using natural language or symbols.

    Args:
        query: Search query (natural language, keywords, or symbols)
        limit: Maximum results
        search_mode: "vector", "text", "relationship", or "hybrid"

    Returns:
        List of matching components
    """
    wrapper = _setup.get_card_framework_wrapper()

    if search_mode == "vector":
        return wrapper.search(query, limit=limit)
    elif search_mode == "text":
        return wrapper.search_by_text(query, limit=limit)
    elif search_mode == "relationship":
        return wrapper.search_by_relationship_text(query, limit=limit)
    else:  # hybrid
        return wrapper.hybrid_search(query, limit=limit)


def find_component_by_symbol(symbol: str) -> Optional[Dict]:
    """
    Find a component by its symbol.

    Args:
        symbol: Component symbol (e.g., "ᵬ" for Button)

    Returns:
        Component info dict or None
    """
    symbols = get_gchat_symbols()

    # Reverse lookup
    reverse = {v: k for k, v in symbols.items()}

    component_name = reverse.get(symbol)
    if not component_name:
        return None

    # Search for the component
    wrapper = _setup.get_card_framework_wrapper()
    results = wrapper.search_by_text(
        component_name, field="name", limit=1, is_phrase=True
    )

    return results[0] if results else None


def search_patterns_for_card(
    description: str,
    limit: int = 5,
    require_positive_feedback: bool = True,
) -> Dict[str, Any]:
    """
    Search for card patterns matching a description.

    This is a high-level convenience method for card tools that:
    1. Extracts DSL symbols from the description (if present)
    2. Uses DSL-aware search for precise pattern matching
    3. Falls back to hybrid V7 search if no DSL
    4. Returns structured results ready for card building

    Args:
        description: Card description (may include DSL notation like "§[δ, Ƀ[ᵬ×2]]")
        limit: Maximum patterns to return
        require_positive_feedback: Only return patterns with positive feedback

    Returns:
        Dict with:
            - has_dsl: Whether DSL was detected
            - dsl: Extracted DSL string (or None)
            - patterns: List of matching patterns with component_paths, instance_params
            - classes: List of matching class definitions
            - query_description: Cleaned description without DSL
    """
    wrapper = _setup.get_card_framework_wrapper()

    # Extract DSL from description
    extracted = wrapper.extract_dsl_from_text(description)

    result = {
        "has_dsl": extracted.get("has_dsl", False),
        "dsl": extracted.get("dsl"),
        "query_description": extracted.get("description", description),
        "patterns": [],
        "classes": [],
    }

    if extracted.get("has_dsl"):
        # Use DSL-aware search for precise matching
        logger.info(f"🔤 DSL search: {extracted['dsl']}")

        # Search for patterns
        pattern_results = wrapper.search_by_dsl(
            text=description,
            limit=limit,
            score_threshold=0.3,
            vector_name="inputs",
            type_filter="instance_pattern",
        )

        # Search for classes
        class_results = wrapper.search_by_dsl(
            text=description,
            limit=limit,
            score_threshold=0.3,
            vector_name="components",
            type_filter="class",
        )

        result["patterns"] = pattern_results
        result["classes"] = class_results
    else:
        # Use hybrid search
        feedback_filter = "positive" if require_positive_feedback else None

        class_results, content_patterns, form_patterns = wrapper.search_hybrid(
            description=description,
            component_paths=None,
            limit=limit,
            token_ratio=1.0,
            content_feedback=feedback_filter,
            form_feedback=feedback_filter,
            include_classes=True,
        )

        result["classes"] = class_results
        result["patterns"] = content_patterns

    logger.info(
        f"Pattern search: {len(result['classes'])} classes, "
        f"{len(result['patterns'])} patterns (DSL={result['has_dsl']})"
    )

    return result


# =============================================================================
# AUTO-GENERATED DSL DOCUMENTATION
# =============================================================================


def get_dsl_documentation(
    include_examples: bool = True, include_hierarchy: bool = True
) -> str:
    """
    Auto-generate COMPACT DSL documentation for MCP tool descriptions.

    Only includes the ~20 most crucial components to keep tool
    descriptions concise. For complete documentation, use skill:// resources.

    Args:
        include_examples: Whether to include usage examples
        include_hierarchy: Whether to include component hierarchy

    Returns:
        Markdown-formatted documentation string (compact)
    """
    symbols = get_gchat_symbols()

    # Crucial components for building cards - organized by role
    CORE_COMPONENTS = {
        "card_structure": ["Card", "CardHeader", "Section"],
        "carousel": ["Carousel", "CarouselCard", "NestedWidget"],
        "containers": ["ButtonList", "ChipList", "Grid", "Columns"],
        "widgets": ["DecoratedText", "TextParagraph", "Image", "Divider"],
        "items": ["Button", "Chip", "GridItem", "Column"],
        "message": ["AccessoryWidget"],  # For message-level buttons
    }

    lines = ["## Card DSL Quick Reference\n"]

    # Core symbols organized by category
    lines.append("### Core Symbols")
    lines.append(
        "**Card:** "
        + ", ".join(
            f"{symbols.get(c, '?')}={c}"
            for c in CORE_COMPONENTS["card_structure"]
            if c in symbols
        )
    )
    lines.append(
        "**Carousel:** "
        + ", ".join(
            f"{symbols.get(c, '?')}={c}"
            for c in CORE_COMPONENTS["carousel"]
            if c in symbols
        )
    )
    lines.append(
        "**Containers:** "
        + ", ".join(
            f"{symbols.get(c, '?')}={c}"
            for c in CORE_COMPONENTS["containers"]
            if c in symbols
        )
    )
    lines.append(
        "**Widgets:** "
        + ", ".join(
            f"{symbols.get(c, '?')}={c}"
            for c in CORE_COMPONENTS["widgets"]
            if c in symbols
        )
    )
    lines.append(
        "**Items:** "
        + ", ".join(
            f"{symbols.get(c, '?')}={c}"
            for c in CORE_COMPONENTS["items"]
            if c in symbols
        )
    )

    # Key containment rules (most common patterns)
    if include_hierarchy:
        lines.append("\n### Containment Rules")
        # Get symbols
        section_sym = symbols.get("Section", "§")
        buttonlist_sym = symbols.get("ButtonList", "Ƀ")
        button_sym = symbols.get("Button", "ᵬ")
        chiplist_sym = symbols.get("ChipList", "ȼ")
        chip_sym = symbols.get("Chip", "ℂ")
        grid_sym = symbols.get("Grid", "ℊ")
        gitem_sym = symbols.get("GridItem", "ǵ")
        columns_sym = symbols.get("Columns", "¢")
        column_sym = symbols.get("Column", "ç")
        dtext_sym = symbols.get("DecoratedText", "δ")
        tpara_sym = symbols.get("TextParagraph", "ʈ")
        image_sym = symbols.get("Image", "ǐ")
        carousel_sym = symbols.get("Carousel", "◦")
        ccard_sym = symbols.get("CarouselCard", "▲")
        nested_sym = symbols.get("NestedWidget", "ŋ")

        lines.append(
            f"- {section_sym} Section → {dtext_sym} {tpara_sym} {image_sym} {buttonlist_sym} {chiplist_sym} {grid_sym} {columns_sym}"
        )
        lines.append(
            f"- {carousel_sym} Carousel → {ccard_sym} CarouselCard → {nested_sym} NestedWidget → {tpara_sym} {buttonlist_sym} {image_sym}"
        )
        lines.append(
            f"- {buttonlist_sym} ButtonList → {button_sym}, {chiplist_sym} ChipList → {chip_sym}"
        )
        lines.append(
            f"- {grid_sym} Grid → {gitem_sym}, {columns_sym} Columns → {column_sym}"
        )

    if include_examples:
        section_sym = symbols.get("Section", "§")
        button_sym = symbols.get("Button", "ᵬ")
        buttonlist_sym = symbols.get("ButtonList", "Ƀ")
        dtext_sym = symbols.get("DecoratedText", "δ")
        grid_sym = symbols.get("Grid", "ℊ")
        gitem_sym = symbols.get("GridItem", "ǵ")
        carousel_sym = symbols.get("Carousel", "◦")
        ccard_sym = symbols.get("CarouselCard", "▲")
        nested_sym = symbols.get("NestedWidget", "ŋ")
        tpara_sym = symbols.get("TextParagraph", "ʈ")

        lines.append("\n### Examples")
        lines.append(f"- `{section_sym}[{dtext_sym}]` → Section with text")
        lines.append(
            f"- `{section_sym}[{dtext_sym}, {buttonlist_sym}[{button_sym}×2]]` → Text + 2 buttons"
        )
        lines.append(
            f"- `{section_sym}[{grid_sym}[{gitem_sym}×4]]` → Grid with 4 items"
        )
        lines.append(f"- `{carousel_sym}[{ccard_sym}×3]` → Carousel with 3 cards")
        lines.append("- Syntax: `×N` = multiplier, `[]` = children, `,` = siblings")

    # Reference to complete docs
    lines.append("\n### More Info")
    lines.append(
        "Read `skill://gchat-cards/` resources for complete docs (100+ components)."
    )

    return "\n".join(lines)


def get_dsl_field_description() -> str:
    """
    Get a compact field description for the structure_dsl parameter.

    Returns a single-line description suitable for Field(description=...).
    """
    symbols = get_gchat_symbols()

    # Core symbols - most commonly used components
    key_mappings = []
    key_components = [
        "Section",
        "DecoratedText",
        "ButtonList",
        "Button",
        "Grid",
        "GridItem",
        "Carousel",
        "CarouselCard",
        "NestedWidget",
    ]

    for comp in key_components:
        if comp in symbols:
            key_mappings.append(f"{symbols[comp]}={comp}")

    return (
        f"DSL structure using symbols. "
        f"Examples: '§[δ, Ƀ[ᵬ×2]]' = Section + text + 2 buttons, "
        f"'◦[▲×3]' = Carousel with 3 cards. "
        f"Symbols: {', '.join(key_mappings)}. "
        f"Read skill://gchat-cards/ for full reference."
    )


def get_tool_examples(max_examples: int = 5) -> List[Dict[str, Any]]:
    """
    Generate dynamic tool examples using symbols from the DAG.

    Creates examples that demonstrate common card patterns with proper
    DSL notation and matching card_params.

    Args:
        max_examples: Maximum number of examples to generate

    Returns:
        List of example dicts with description, card_description, card_params
    """
    symbols = get_gchat_symbols()

    # Get symbols for common components (with fallbacks)
    section = symbols.get("Section", "§")
    dtext = symbols.get("DecoratedText", "δ")
    btnlist = symbols.get("ButtonList", "Ƀ")
    btn = symbols.get("Button", "ᵬ")
    grid = symbols.get("Grid", "ℊ")
    gitem = symbols.get("GridItem", "ǵ")
    chiplist = symbols.get("ChipList", "ȼ")
    chip = symbols.get("Chip", "ℂ")
    carousel = symbols.get("Carousel", "◦")
    ccard = symbols.get("CarouselCard", "▲")
    image = symbols.get("Image", "Ɨ")
    divider = symbols.get("Divider", "Đ")

    # Define examples using dynamic symbols
    all_examples = [
        {
            "description": "Simple text card",
            "card_description": f"{section}[{dtext}]",
            "card_params": {"title": "Alert", "text": "System update complete"},
        },
        {
            "description": "Text + 2 action buttons",
            "card_description": f"{section}[{dtext}, {btnlist}[{btn}×2]]",
            "card_params": {
                "title": "Actions Required",
                "text": "Choose an action",
                "buttons": [
                    {"text": "Approve", "url": "https://example.com/yes"},
                    {"text": "Reject", "url": "https://example.com/no"},
                ],
            },
        },
        {
            "description": "Grid with 4 items",
            "card_description": f"{section}[{grid}[{gitem}×4]]",
            "card_params": {
                "title": "Gallery",
                "images": [
                    "https://picsum.photos/200/200?1",
                    "https://picsum.photos/200/200?2",
                    "https://picsum.photos/200/200?3",
                    "https://picsum.photos/200/200?4",
                ],
            },
        },
        {
            "description": "Jinja styled status text",
            "card_description": f"{section}[{dtext}]",
            "card_params": {
                "title": "System Status",
                "text": "Server: {{ 'Online' | success_text }} | DB: {{ 'Warning' | warning_text }}",
            },
        },
        {
            "description": "Chip list for quick selection",
            "card_description": f"{section}[{dtext}, {chiplist}[{chip}×3]]",
            "card_params": {
                "title": "Select Tags",
                "text": "Choose categories",
                "chips": [
                    {"text": "Bug", "url": "#bug"},
                    {"text": "Feature", "url": "#feature"},
                    {"text": "Docs", "url": "#docs"},
                ],
            },
        },
        {
            "description": "Carousel with 3 cards",
            "card_description": f"{carousel}[{ccard}×3]",
            "card_params": {
                "title": "Recent Items",
                "cards": [
                    {"title": "Card 1", "text": "First item"},
                    {"title": "Card 2", "text": "Second item"},
                    {"title": "Card 3", "text": "Third item"},
                ],
            },
        },
        {
            "description": "Image with text and divider",
            "card_description": f"{section}[{image}, {divider}, {dtext}]",
            "card_params": {
                "title": "Featured",
                "image_url": "https://picsum.photos/400/200",
                "text": "Featured content description",
            },
        },
    ]

    return all_examples[:max_examples]


def get_hierarchy_tree_text(
    root_components: Optional[List[str]] = None,
    max_depth: int = 3,
    include_symbols: bool = True,
) -> str:
    """
    Generate a deterministic text-based tree representation of component hierarchy.

    Delegates to ModuleWrapper.get_hierarchy_tree_text() for the actual implementation.

    Args:
        root_components: Optional list of root component names to start from.
                        If None, uses common card containers (Card, Section, etc.)
        max_depth: Maximum depth to traverse (default 3)
        include_symbols: Whether to include symbols in the output

    Returns:
        ASCII tree representation of the hierarchy
    """
    wrapper = _setup.get_card_framework_wrapper()

    # Default root components for gchat cards
    if root_components is None:
        root_components = ["Card", "Section", "DecoratedText", "Grid", "ButtonList"]

    return wrapper.get_hierarchy_tree_text(
        root_components=root_components,
        max_depth=max_depth,
        include_symbols=include_symbols,
    )


def get_full_hierarchy_documentation(include_tree: bool = True) -> str:
    """
    Generate complete hierarchy documentation with symbols and tree visualization.

    Delegates to ModuleWrapper.get_full_module_documentation().

    Args:
        include_tree: Whether to include the ASCII tree visualization

    Returns:
        Complete markdown documentation string
    """
    wrapper = _setup.get_card_framework_wrapper()

    return wrapper.get_full_module_documentation(
        include_tree=include_tree,
        include_symbols=True,
        include_examples=True,
    )


def get_component_relationships_for_dsl() -> Dict[str, List[str]]:
    """
    Get component relationships formatted for DSL validation.

    Returns a dict mapping parent components to their valid children,
    using component names (not symbols).

    Dynamically loads relationships from Qdrant and expands base class
    references (e.g., Widget) to actual widget subclasses via Python introspection.
    """
    wrapper = _setup.get_card_framework_wrapper()
    relationships = {}

    # Step 1: Get Widget subclasses via Python introspection (most accurate)
    widget_subclasses = _get_widget_subclasses()
    logger.info(
        f"📦 Found {len(widget_subclasses)} Widget subclasses via introspection"
    )

    if not wrapper.client:
        logger.warning("No Qdrant client - using introspection-based relationships")
        return _build_relationships_from_introspection(widget_subclasses)

    try:
        from qdrant_client import models

        # Step 2: Get all classes with their relationships from Qdrant
        results, _ = wrapper.client.scroll(
            collection_name=wrapper.collection_name,
            scroll_filter=models.Filter(
                must=[
                    models.FieldCondition(
                        key="type",
                        match=models.MatchValue(value="class"),
                    )
                ]
            ),
            limit=300,
            with_payload=["name", "relationships"],
        )

        # Step 3: Build relationships, expanding Widget -> all widget subclasses
        for point in results:
            payload = point.payload
            name = payload.get("name")
            rels = payload.get("relationships", {})
            children = rels.get("child_classes", [])

            if name and children:
                # Expand "Widget" to all actual widget subclasses
                expanded_children = []
                for child in children:
                    if child == "Widget":
                        # Replace Widget with all subclasses from introspection
                        expanded_children.extend(widget_subclasses)
                    else:
                        expanded_children.append(child)

                relationships[name] = expanded_children

        logger.info(
            f"📋 Loaded {len(relationships)} component relationships for DSL (Qdrant + introspection)"
        )

        # Log Section's children for debugging
        section_children = relationships.get("Section", [])
        logger.info(
            f"📋 Section can contain: {len(section_children)} widget types: {section_children}"
        )

        return relationships

    except Exception as e:
        logger.warning(f"Failed to load relationships from Qdrant: {e}")
        return _build_relationships_from_introspection(widget_subclasses)


def _get_widget_subclasses() -> List[str]:
    """Get all Widget subclasses via Python introspection."""
    try:
        from card_framework.v2.widget import Widget

        def get_all_subclasses(cls):
            all_subs = []
            for sub in cls.__subclasses__():
                all_subs.append(sub)
                all_subs.extend(get_all_subclasses(sub))
            return all_subs

        subclasses = get_all_subclasses(Widget)
        return sorted([c.__name__ for c in subclasses])
    except ImportError:
        logger.warning("Could not import Widget class for introspection")
        return [
            "Action",
            "Button",
            "ButtonList",
            "Chip",
            "ChipList",
            "Columns",
            "DateTimePicker",
            "DecoratedText",
            "Divider",
            "Grid",
            "Image",
            "SelectionInput",
            "SwitchControl",
            "TextInput",
            "TextParagraph",
            "UpdatedWidget",
        ]


def _build_relationships_from_introspection(
    widget_subclasses: List[str],
) -> Dict[str, List[str]]:
    """Build relationships using Python introspection when Qdrant is unavailable.

    This includes manually-added Google Chat API components that may not exist
    in the card_framework Python package but are supported by the Chat API.
    Custom components are defined in CUSTOM_CHAT_API_RELATIONSHIPS.
    """
    # Base relationships from card_framework introspection
    base_relationships = {
        "Card": ["CardHeader", "Section", "CardFixedFooter", "Carousel"],
        "Section": ["CollapseControl"] + widget_subclasses,
        "Columns": ["Column"],
        "Column": widget_subclasses,  # Column can contain any widget
        "ButtonList": ["Button"],
        "ChipList": ["Chip"],
        "Grid": ["GridItem"],
        "DecoratedText": ["Icon", "Button", "OnClick", "SwitchControl"],
        "Button": ["Icon", "OnClick", "Color"],
        "Chip": ["Icon", "OnClick"],
        "OnClick": ["OpenLink", "Action", "OverflowMenu"],
        "OverflowMenu": ["OverflowMenuItem"],
        "GridItem": ["ImageComponent"],
        "TextInput": ["Suggestions", "Validation"],
    }

    # Merge with custom Chat API relationships (avoids duplication)
    base_relationships.update(_setup.CUSTOM_CHAT_API_RELATIONSHIPS)

    return base_relationships


# =============================================================================
# DSL PARSING HELPERS (using refactored module_wrapper.dsl_parser)
# =============================================================================


def get_dsl_parser():
    """
    Get a configured DSL parser for gchat card components.

    Uses the new refactored DSLParser from adapters.module_wrapper.dsl_parser
    which provides:
    - Robust tokenization and parsing
    - Qdrant query generation
    - DSL extraction from descriptions
    - Validation against component hierarchy

    Returns:
        DSLParser instance configured with gchat symbols and relationships
    """
    from adapters.module_wrapper.dsl_parser import DSLParser

    symbols = get_gchat_symbols()
    relationships = get_component_relationships_for_dsl()

    return DSLParser(
        symbol_mapping=symbols,
        reverse_mapping={v: k for k, v in symbols.items()},
        relationships=relationships,
    )


def parse_dsl(dsl_string: str):
    """
    Parse a DSL string using the refactored DSL parser.

    Args:
        dsl_string: DSL notation like "§[đ×3, Ƀ[ᵬ×2]]"

    Returns:
        DSLParseResult with:
        - is_valid: Whether structure is valid
        - component_counts: Dict of component name → count
        - component_paths: Flat list of component names
        - root_nodes: Parsed tree structure
        - issues: List of validation issues

    Example:
        result = parse_dsl("§[đ×3, Ƀ[ᵬ×2]]")
        if result.is_valid:
            print(result.component_counts)
            # {'Section': 1, 'DecoratedText': 3, 'ButtonList': 1, 'Button': 2}
    """
    parser = get_dsl_parser()
    return parser.parse(dsl_string)


def extract_dsl_from_description(description: str) -> Optional[str]:
    """
    Extract DSL notation from a description string.

    Uses the refactored DSL parser for robust extraction.

    Args:
        description: Text that may contain DSL notation
                    e.g., "§[đ×3, Ƀ[ᵬ×2]] Server Status Dashboard"

    Returns:
        DSL string if found, None otherwise
        e.g., "§[δ×3, Ƀ[ᵬ×2]]"

    Example:
        dsl = extract_dsl_from_description("§[đ×3] Server Status")
        # Returns: "§[đ×3]"
    """
    if not description:
        return None

    parser = get_dsl_parser()
    return parser.extract_dsl_from_text(description)


def dsl_to_qdrant_queries(
    dsl_string: str, collection_name: Optional[str] = None
) -> List[Dict]:
    """
    Generate Qdrant queries from a DSL string.

    Uses the refactored DSL parser to generate optimized queries
    for the relationships, components, and inputs vectors.

    Args:
        dsl_string: DSL notation
        collection_name: Qdrant collection name (uses settings.card_collection if None)

    Returns:
        List of query dicts with:
        - vector_name: Which vector to search ('relationships', 'components', 'inputs')
        - query_text: The query text
        - filters: Any filters to apply

    Example:
        queries = dsl_to_qdrant_queries("§[đ×3, Ƀ[ᵬ×2]]")
        for q in queries:
            print(f"{q['vector_name']}: {q['query_text']}")
    """
    from config.settings import settings

    parser = get_dsl_parser()
    result = parser.parse(dsl_string)

    if not result.is_valid:
        logger.warning(f"Invalid DSL structure: {result.issues}")
        return []

    collection = collection_name or settings.card_collection
    queries = parser.to_qdrant_queries(result, collection)

    return [q.to_dict() for q in queries]


def validate_dsl(dsl_string: str) -> tuple:
    """
    Validate a DSL structure against the component hierarchy.

    Args:
        dsl_string: DSL notation to validate

    Returns:
        Tuple of (is_valid, issues_list)

    Example:
        is_valid, issues = validate_dsl("§[đ, ᵬ]")
        if not is_valid:
            print(f"Issues: {issues}")
    """
    parser = get_dsl_parser()
    result = parser.parse(dsl_string)
    return result.is_valid, result.issues


def expand_dsl(dsl_string: str) -> str:
    """
    Expand DSL symbols to full component names.

    Args:
        dsl_string: Compact DSL like "§[đ, ᵬ×2]"

    Returns:
        Expanded notation like "Section[DecoratedText, Button×2]"
    """
    parser = get_dsl_parser()
    return parser.expand_dsl(dsl_string)


def compact_dsl(component_notation: str) -> str:
    """
    Compact component names to DSL symbols.

    Args:
        component_notation: Full names like "Section[DecoratedText, Button×2]"

    Returns:
        Compact DSL like "§[đ, ᵬ×2]"
    """
    parser = get_dsl_parser()
    return parser.compact_to_dsl(component_notation)


# =============================================================================
# CONTENT DSL HELPERS
# =============================================================================


def parse_content_dsl(content_text: str):
    """
    Parse Content DSL text into structured blocks.

    Content DSL allows expressing component content with styling modifiers:

        δ 'Status: Online' success bold
        ᵬ Click Here https://example.com
          Continue on next line

    Features:
        - Symbol prefix indicates component type (δ, ᵬ, §, etc.)
        - Quoted or unquoted text content
        - Style modifiers (yellow, bold, success, error, italic, etc.)
        - URL detection for button/link actions
        - Continuation lines (indented) for multi-line content

    Args:
        content_text: Multi-line Content DSL text

    Returns:
        ContentDSLResult with:
        - is_valid: Whether parsing succeeded
        - blocks: List of ContentBlock objects
        - issues: Any parsing issues

    Example:
        result = parse_content_dsl('''
            § Dashboard bold
            δ 'Server Status' success
            ᵬ Refresh https://api.example.com/refresh
        ''')

        for block in result.blocks:
            print(f"{block.primary.component_name}: {block.to_jinja()}")
    """
    parser = get_dsl_parser()
    return parser.parse_content_dsl(content_text)


def content_to_jinja(content_text: str) -> List[str]:
    """
    Convert Content DSL directly to Jinja expressions.

    A convenience function that parses Content DSL and returns
    the Jinja template expressions for each block.

    Args:
        content_text: Content DSL text

    Returns:
        List of Jinja expressions like ["{{ 'text' | success_text | bold }}"]

    Example:
        expressions = content_to_jinja("δ 'Hello' success bold")
        # Returns: ["{{ 'Hello' | success_text | bold }}"]
    """
    parser = get_dsl_parser()
    result = parser.parse_content_dsl(content_text)
    return result.to_jinja_list()


def content_to_params(content_text: str) -> List[Dict]:
    """
    Convert Content DSL to component parameter dictionaries.

    Useful for directly building card components without going
    through the Jinja template system.

    Args:
        content_text: Content DSL text

    Returns:
        List of dicts with component parameters:
        - component: Component name (e.g., "DecoratedText")
        - text: The text content
        - jinja_text: Jinja-formatted text with filters
        - url: URL if detected (for buttons)
        - styles: List of style modifier names

    Example:
        params = content_to_params('''
            δ 'Server Online' success
            ᵬ Refresh https://api.example.com
        ''')
        # Returns:
        # [
        #   {"component": "DecoratedText", "text": "Server Online", "styles": ["success"], ...},
        #   {"component": "Button", "text": "Refresh", "url": "https://api.example.com", ...}
        # ]
    """
    parser = get_dsl_parser()
    result = parser.parse_content_dsl(content_text)
    return parser.content_to_component_params(result)


def get_available_style_modifiers() -> Dict[str, str]:
    """
    Get available style modifiers for Content DSL.

    Returns:
        Dict mapping modifier name to Jinja filter name

    Example:
        modifiers = get_available_style_modifiers()
        # {'bold': 'bold', 'success': 'success_text', 'yellow': 'color', ...}
    """
    from adapters.module_wrapper.dsl_parser import STYLE_MODIFIERS

    return {name: filter_info[0] for name, filter_info in STYLE_MODIFIERS.items()}
