"""
Variation Generator - Thin Wrapper for Backwards Compatibility

This module provides backwards-compatible convenience functions for variation
generation. The actual implementation is in instance_pattern_mixin.py.

For new code, prefer using the ModuleWrapper methods directly:
    wrapper.store_instance_pattern(..., generate_variations=True)
    wrapper.generate_pattern_variations(pattern)
    wrapper.get_cached_variation(pattern_id)

This module is maintained for backwards compatibility with existing code
that uses VariationGenerator and related classes directly.
"""

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

from adapters.module_wrapper.types import (
    ComponentPaths,
    DSLNotation,
    Payload,
    RelationshipDict,
)

logger = logging.getLogger(__name__)

# Re-export from instance_pattern_mixin for backwards compatibility
from adapters.module_wrapper.instance_pattern_mixin import (
    InstancePattern,
    ParameterVariator,
    StructureVariator,
    VariationFamily,
)
from adapters.module_wrapper.instance_pattern_mixin import (
    PatternVariation as Variation,  # Alias for backwards compatibility
)


class VariationGenerator:
    """
    Backwards-compatible variation generator.

    Wraps the generic InstancePatternMixin functionality for use with
    any ModuleWrapper instance.

    For new code, prefer using wrapper methods directly:
        wrapper.generate_pattern_variations(pattern)
        wrapper.get_cached_variation(pattern_id)
    """

    def __init__(self, wrapper=None):
        """
        Initialize the variation generator.

        Args:
            wrapper: ModuleWrapper instance (optional, will be fetched lazily)
        """
        self.wrapper = wrapper
        self._initialized = False

    def _ensure_wrapper(self):
        """Ensure wrapper is available."""
        if self.wrapper is None:
            try:
                from gchat.card_framework_wrapper import get_card_framework_wrapper

                self.wrapper = get_card_framework_wrapper()
            except ImportError:
                logger.warning("Could not get card_framework_wrapper")

        return self.wrapper

    def generate_variations(
        self,
        pattern: Payload,
        num_structure_variations: int = 3,
        num_param_variations: int = 2,
        cache_variations: bool = True,
    ) -> Optional[VariationFamily]:
        """
        Generate variations of a pattern.

        Delegates to the wrapper's InstancePatternMixin methods.

        Args:
            pattern: Pattern dict with component_paths and instance_params
            num_structure_variations: Number of structural variations
            num_param_variations: Number of parameter variations per structure
            cache_variations: Whether to cache variations

        Returns:
            VariationFamily or None
        """
        wrapper = self._ensure_wrapper()
        if not wrapper:
            logger.warning("No wrapper available for variation generation")
            return None

        # Convert dict pattern to InstancePattern
        component_paths = pattern.get("component_paths") or pattern.get(
            "parent_paths", []
        )
        instance_params = pattern.get("instance_params", {})
        description = pattern.get("card_description", "")
        pattern_id = pattern.get("card_id") or pattern.get("id", "")

        instance_pattern = InstancePattern(
            pattern_id=pattern_id,
            component_paths=component_paths,
            instance_params=instance_params,
            description=description,
            dsl_notation=pattern.get("dsl_notation"),
            feedback=pattern.get("feedback") or pattern.get("content_feedback"),
        )

        # Delegate to wrapper's mixin method
        if hasattr(wrapper, "generate_pattern_variations"):
            return wrapper.generate_pattern_variations(
                pattern=instance_pattern,
                num_structure_variations=num_structure_variations,
                num_param_variations=num_param_variations,
                cache_variations=cache_variations,
            )

        # Fallback: use structure/param variators directly
        struct_variator = StructureVariator(getattr(wrapper, "relationships", {}))
        param_variator = ParameterVariator()

        family = VariationFamily(
            parent_id=instance_pattern.pattern_id,
            source_pattern=instance_pattern,
        )

        # Generate structure variations
        struct_variations = struct_variator.generate_variations(
            component_paths,
            num_structure_variations,
        )

        all_structures = [component_paths] + struct_variations

        variation_idx = 0
        for struct_idx, struct_paths in enumerate(all_structures):
            if struct_idx == 0:
                param_sets = [instance_params] + param_variator.generate_variations(
                    instance_params, num_param_variations - 1
                )
            else:
                param_sets = param_variator.generate_variations(
                    instance_params, num_param_variations
                )

            for param_idx, params in enumerate(param_sets):
                var_type = (
                    "original"
                    if struct_idx == 0 and param_idx == 0
                    else "structure"
                    if struct_idx > 0
                    else "parameter"
                )

                variation = Variation(
                    variation_id=f"{instance_pattern.pattern_id}:v{variation_idx}",
                    variation_type=var_type,
                    component_paths=struct_paths,
                    instance_params=params,
                    parent_id=instance_pattern.pattern_id,
                    cache_key=f"{instance_pattern.pattern_id}:v{variation_idx}",
                )

                family.variations.append(variation)
                family.cache_keys.append(variation.cache_key)
                variation_idx += 1

        return family

    def get_family(self, parent_key: str) -> Optional[VariationFamily]:
        """Get a variation family by parent key."""
        wrapper = self._ensure_wrapper()
        if wrapper and hasattr(wrapper, "get_variation_family"):
            return wrapper.get_variation_family(parent_key)
        return None

    def get_random_variation(self, parent_key: str) -> Optional[Variation]:
        """Get a random variation from a family."""
        wrapper = self._ensure_wrapper()
        if wrapper and hasattr(wrapper, "get_random_variation"):
            return wrapper.get_random_variation(parent_key)
        return None

    def get_variation_by_type(
        self,
        parent_key: str,
        variation_type: str,
    ) -> Optional[Variation]:
        """Get a variation of specific type from a family."""
        wrapper = self._ensure_wrapper()
        if wrapper and hasattr(wrapper, "get_random_variation"):
            return wrapper.get_random_variation(parent_key, variation_type)
        return None

    def list_families(self) -> List[str]:
        """List all tracked family keys."""
        wrapper = self._ensure_wrapper()
        if wrapper and hasattr(wrapper, "_get_variation_families"):
            return list(wrapper._get_variation_families().keys())
        return []

    @property
    def stats(self) -> Payload:
        """Get generator statistics."""
        wrapper = self._ensure_wrapper()
        if wrapper and hasattr(wrapper, "pattern_stats"):
            return wrapper.pattern_stats
        return {
            "num_families": 0,
            "total_variations": 0,
            "avg_variations_per_family": 0,
        }


# =============================================================================
# CONVENIENCE FUNCTIONS (Backwards Compatibility)
# =============================================================================

_generator_instance: Optional[VariationGenerator] = None


def get_variation_generator() -> VariationGenerator:
    """
    Get the singleton variation generator.

    For new code, prefer using wrapper methods directly.
    """
    global _generator_instance
    if _generator_instance is None:
        _generator_instance = VariationGenerator()
    return _generator_instance


def generate_and_cache_variations(
    pattern: Payload,
    num_structure_variations: int = 3,
    num_param_variations: int = 2,
) -> Optional[VariationFamily]:
    """
    Convenience function to generate and cache variations.

    For new code, prefer using wrapper methods directly.

    Args:
        pattern: Source pattern
        num_structure_variations: Structural variations count
        num_param_variations: Parameter variations per structure

    Returns:
        VariationFamily with all generated variations
    """
    generator = get_variation_generator()
    return generator.generate_variations(
        pattern,
        num_structure_variations,
        num_param_variations,
    )
