"""Variable resolution for PromptCanvas SDK."""

import re
from typing import Dict, List, Union, Callable

VariableValue = Union[str, int, float, bool]


class VariableResolver:
    """
    Fast variable resolver for prompt templates.
    
    Supports {{ variable }} and {{variable}} syntax.
    """

    PATTERN = re.compile(r"\{\{\s*(\w+)\s*\}\}")

    @classmethod
    def resolve(
        cls,
        template: str,
        variables: Dict[str, VariableValue],
    ) -> str:
        """
        Resolve variables in a template string.
        
        Args:
            template: The template with {{ variable }} placeholders
            variables: Key-value pairs to substitute
            
        Returns:
            Resolved string with variables replaced
            
        Example:
            >>> VariableResolver.resolve("Hello {{ name }}!", {"name": "World"})
            "Hello World!"
        """
        if not template or not variables:
            return template

        def replacer(match: re.Match) -> str:
            var_name = match.group(1)
            if var_name in variables:
                return str(variables[var_name])
            return match.group(0)  # Keep original if no value

        return cls.PATTERN.sub(replacer, template)

    @classmethod
    def extract(cls, template: str) -> List[str]:
        """
        Extract variable names from a template.
        
        Args:
            template: The template string
            
        Returns:
            List of unique variable names found
            
        Example:
            >>> VariableResolver.extract("Hello {{ name }}, order {{ id }}")
            ["name", "id"]
        """
        if not template:
            return []

        matches = cls.PATTERN.findall(template)
        # Return unique values while preserving order
        seen = set()
        result = []
        for match in matches:
            if match not in seen:
                seen.add(match)
                result.append(match)
        return result

    @classmethod
    def validate(
        cls,
        template: str,
        variables: Dict[str, VariableValue],
    ) -> tuple:
        """
        Validate that all required variables are provided.
        
        Args:
            template: The template string
            variables: Provided variables
            
        Returns:
            Tuple of (valid: bool, missing: List[str])
            
        Example:
            >>> VariableResolver.validate("{{ a }} {{ b }}", {"a": "1"})
            (False, ["b"])
        """
        required = cls.extract(template)
        missing = [v for v in required if v not in variables]
        return (len(missing) == 0, missing)

    @classmethod
    def create_with_globals(
        cls,
        global_variables: Dict[str, VariableValue],
    ) -> Callable[[str, Dict[str, VariableValue]], str]:
        """
        Create a resolver with pre-set global variables.
        
        Args:
            global_variables: Variables to include in every resolution
            
        Returns:
            A resolver function that merges globals with local variables
            
        Example:
            >>> resolver = VariableResolver.create_with_globals({"app": "MyApp"})
            >>> resolver("Welcome to {{ app }}, {{ user }}!", {"user": "John"})
            "Welcome to MyApp, John!"
        """
        def resolver(
            template: str,
            local_variables: Dict[str, VariableValue] = None,
        ) -> str:
            merged = {**global_variables, **(local_variables or {})}
            return cls.resolve(template, merged)

        return resolver
