"""
Singleton ModuleWrapper for card_framework.

This provides a single shared ModuleWrapper instance for all gchat modules
that need to access card_framework components. Avoids redundant wrapper
creation and ensures consistent configuration.

Features:
    - Singleton pattern for shared access
    - Text indices for keyword/phrase search
    - Symbol generation for compact DSL notation
    - Styling registry for color/formatting rules

Usage:
    from gchat.card_framework_wrapper import get_card_framework_wrapper

    wrapper = get_card_framework_wrapper()

    # Vector search
    results = wrapper.search("button with icon")

    # Text search (keyword)
    results = wrapper.search_by_text("Button", field="name")

    # Relationship search
    results = wrapper.search_by_relationship_text("clickable image")

    # Hybrid search (text + vector)
    results = wrapper.hybrid_search("decorated text with button")

    # Get symbols for DSL
    symbols = get_gchat_symbols()
"""

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

from config.enhanced_logging import setup_logger

logger = setup_logger(__name__)

# Thread-safe singleton
_wrapper: Optional["ModuleWrapper"] = None
_wrapper_lock = threading.Lock()

# Cached symbols
_symbols: Optional[Dict[str, str]] = None
_symbols_lock = threading.Lock()

# =============================================================================
# GCHAT-SPECIFIC CONFIGURATION
# =============================================================================

# Google Chat Card API Limits
GCHAT_CARD_MAX_BYTES = 20_000  # Maximum card payload size
GCHAT_TEXT_MAX_CHARS = 18_000  # Maximum text message length
GCHAT_SAFE_LIMIT_RATIO = 0.75  # Recommended operating ratio (75% of max)
GCHAT_SAFE_CARD_BYTES = int(GCHAT_CARD_MAX_BYTES * GCHAT_SAFE_LIMIT_RATIO)  # ~15KB

# Domain-specific stopwords for gchat card search
GCHAT_STOPWORDS = [
    "widget",  # Too generic
    "component",  # Too generic
    "google",  # Domain noise
    "chat",  # Domain noise
    "card",  # Everything is a card
    "framework",  # Module name noise
]

# NOTE: Symbols are auto-generated by SymbolGenerator based on LETTER_SYMBOLS pools.
# No hardcoded overrides - ModuleWrapper.generate_component_symbols() is the SSoT.
# See adapters/symbol_generator.py:LETTER_SYMBOLS for the character pools.


# =============================================================================
# SINGLETON ACCESS
# =============================================================================


def get_card_framework_wrapper(
    force_reinitialize: bool = False,
    ensure_text_indices: bool = True,
) -> "ModuleWrapper":
    """
    Get the singleton ModuleWrapper for card_framework.

    This wrapper is shared across:
        - SmartCardBuilder
        - TemplateComponent
        - card_tools
        - CardBuilderV2
        - Any other gchat modules needing card_framework access

    Args:
        force_reinitialize: If True, recreate the wrapper even if one exists.
                           Use sparingly (e.g., after collection schema changes).
        ensure_text_indices: If True, ensure text indices exist on first init.

    Returns:
        Shared ModuleWrapper instance configured for card_framework
    """
    global _wrapper

    with _wrapper_lock:
        if _wrapper is None or force_reinitialize:
            _wrapper = _create_wrapper(ensure_text_indices=ensure_text_indices)

    return _wrapper


def _create_wrapper(ensure_text_indices: bool = True) -> "ModuleWrapper":
    """Create and configure the ModuleWrapper instance."""
    from adapters.module_wrapper import ModuleWrapper
    from config.settings import settings

    logger.info("🔧 Creating singleton ModuleWrapper for card_framework...")

    wrapper = ModuleWrapper(
        module_or_name="card_framework",
        qdrant_url=settings.qdrant_url,
        qdrant_api_key=settings.qdrant_api_key,
        collection_name=settings.card_collection,  # mcp_gchat_cards_v7
        auto_initialize=False,  # Don't re-index, collection already populated
        index_nested=True,
        index_private=False,
        max_depth=5,  # Capture full component hierarchy
        skip_standard_library=True,
    )

    # Initialize Qdrant client for text index operations
    wrapper.initialize()

    component_count = len(wrapper.components) if wrapper.components else 0
    logger.info(f"✅ Singleton ModuleWrapper ready: {component_count} components")

    # Create text indices if requested (idempotent - skips if exists)
    if ensure_text_indices and wrapper.client:
        try:
            logger.info("📝 Ensuring text indices exist...")
            indices_created = wrapper.create_text_indices(
                enable_stemming=True,
                enable_stopwords=True,
                enable_phrase_matching=True,
                enable_ascii_folding=True,
                custom_stopwords=GCHAT_STOPWORDS,
            )
            if indices_created > 0:
                logger.info(f"✅ Created {indices_created} new text indices")
            else:
                logger.debug("Text indices already exist")
        except Exception as e:
            logger.warning(f"⚠️ Failed to create text indices: {e}")

    return wrapper


def reset_wrapper():
    """
    Reset the singleton wrapper and cached symbols.

    Use this when you need to force reinitialization, such as:
        - After updating the Qdrant collection schema
        - During testing
        - After configuration changes
    """
    global _wrapper, _symbols

    with _wrapper_lock:
        if _wrapper is not None:
            logger.info("🔄 Resetting singleton ModuleWrapper")
            _wrapper = None

    with _symbols_lock:
        _symbols = None


# =============================================================================
# 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": "ᵬ"})
    """
    global _symbols

    with _symbols_lock:
        if _symbols is None or force_regenerate:
            _symbols = _generate_gchat_symbols()

    return _symbols


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

    IMPORTANT: Symbols are loaded FROM Qdrant, not regenerated, to ensure
    consistency between queries and stored data. The symbols were embedded
    into the collection at indexing time.
    """
    wrapper = get_card_framework_wrapper(ensure_text_indices=False)

    symbols = {}

    # LOAD symbols directly from Qdrant's symbol payload field
    # This ensures runtime symbols match what's indexed
    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 (SSoT)")
                return symbols

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

    # Fallback: Generate symbols if Qdrant unavailable
    logger.warning("⚠️ Falling back to symbol generation (Qdrant unavailable)")
    from adapters.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())

    # 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 = 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 = 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


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


def get_dsl_documentation(
    include_examples: bool = True, include_hierarchy: bool = True
) -> str:
    """
    Auto-generate DSL documentation from the symbol table and relationships.

    This creates a dynamic docstring that reflects the current symbols
    and component hierarchy, suitable for MCP tool descriptions.

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

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

    lines = ["## Card Structure DSL\n"]
    lines.append("Google Chat cards are built from dataclass components.")
    lines.append("Each component has a unique symbol for compact structure notation.\n")

    # Auto-generated symbol table (grouped by first letter)
    lines.append("### Symbol Mappings (auto-generated)\n")
    from collections import defaultdict

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

    for letter in sorted(by_letter.keys()):
        mappings = by_letter[letter]
        if len(mappings) <= 4:
            lines.append(f"**{letter}:** {', '.join(mappings)}")
        else:
            # Show first 4 for brevity
            lines.append(f"**{letter}:** {', '.join(mappings[:4])}...")

    # Add hierarchy section (structural parent-child from dataclass fields)
    if include_hierarchy and relationships:
        lines.append("\n### Component Hierarchy (from dataclass fields)\n")
        lines.append("Shows which components can contain which (parent → children):\n")

        # Show hierarchy with symbols
        for parent, children in sorted(relationships.items()):
            parent_sym = symbols.get(parent, parent)
            child_syms = []
            for child in children[:5]:  # Limit for readability
                child_sym = symbols.get(child, child)
                child_syms.append(f"{child_sym}={child}")

            if len(children) > 5:
                child_syms.append(f"+{len(children) - 5} more")

            lines.append(f"- {parent_sym} **{parent}** → [{', '.join(child_syms)}]")

    # Build syntax examples using actual symbols
    section_sym = symbols.get("Section", "§")
    button_sym = symbols.get("Button", "ᵬ")
    dtext_sym = symbols.get("DecoratedText", "đ")
    grid_sym = symbols.get("Grid", "ℊ")
    gitem_sym = symbols.get("GridItem", "ǵ")

    lines.append("\n### DSL Syntax\n")
    lines.append(
        f"- `{section_sym}[{dtext_sym}, {button_sym}]` → Section with DecoratedText and Button"
    )
    lines.append(f"- `{button_sym}×2` → 2 Buttons (multiplier notation)")
    lines.append(f"- `{grid_sym}[{gitem_sym}×4]` → Grid with 4 GridItems")
    lines.append("- Nesting: `parent[child1, child2[grandchild]]`")

    if include_examples:
        lines.append("\n### Examples\n")
        lines.append("```python")
        lines.append("# Simple card with text and button")
        lines.append(f'structure_dsl="{section_sym}[{dtext_sym}, {button_sym}]"')
        lines.append('card_params={"text": "Hello", "button_text": "Click"}')
        lines.append("")
        lines.append("# Grid with 6 items")
        lines.append(f'structure_dsl="{section_sym}[{grid_sym}[{gitem_sym}×6]]"')
        lines.append("```")

    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()

    # Get key symbols for the description
    key_mappings = []
    key_components = [
        "Section",
        "DecoratedText",
        "Button",
        "ButtonList",
        "Grid",
        "GridItem",
        "Image",
        "Icon",
        "TextInput",
        "OnClick",
    ]

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

    return (
        f"DSL structure using symbols. "
        f"Example: '§[đ, Ƀ[ᵬ×2]]' = Section with DecoratedText and 2 Buttons. "
        f"Symbols: {', '.join(key_mappings[:8])}..."
    )


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 = 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 = 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).
    """
    wrapper = get_card_framework_wrapper()

    # Try to get from Qdrant first
    relationships = {}
    if wrapper.client:
        try:
            from qdrant_client import models

            results, _ = wrapper.client.scroll(
                collection_name=wrapper.collection_name,
                scroll_filter=models.Filter(
                    must=[
                        models.FieldCondition(
                            key="type",
                            match=models.MatchValue(value="class"),
                        )
                    ]
                ),
                limit=200,
                with_payload=["name", "relationships"],
            )

            for point in results:
                name = point.payload.get("name")
                rels = point.payload.get("relationships", {})
                children = rels.get("child_classes", [])
                if name and children:
                    relationships[name] = children

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

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

    # Fallback defaults
    return {
        "Card": ["Header", "Section", "CardFixedFooter"],
        "Section": [
            "DecoratedText",
            "TextParagraph",
            "ButtonList",
            "Grid",
            "Divider",
            "Image",
            "Columns",
            "SelectionInput",
            "TextInput",
            "DateTimePicker",
            "ChipList",
        ],
        "Columns": ["Column"],
        "Column": ["DecoratedText", "TextParagraph", "Image", "ButtonList"],
        "ButtonList": ["Button"],
        "ChipList": ["Chip"],
        "Grid": ["GridItem"],
        "DecoratedText": ["Icon", "Button", "OnClick", "SwitchControl"],
        "Button": ["Icon", "OnClick"],
        "Chip": ["Icon", "OnClick"],
        "OnClick": ["OpenLink", "Action", "OverflowMenu"],
        "OverflowMenu": ["OverflowMenuItem"],
    }


# =============================================================================
# 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()}
