"""
Resolution strategies for multi-space artifact lookup.

Implements FR-3.1: Deterministic resolution order
"""

from abc import ABC, abstractmethod
from typing import List, Optional
from dataclasses import dataclass, field


@dataclass
class ResolutionConfig:
    """
    Configuration for resolution strategy.

    Implements FR-3.1: Resolution order configuration

    Resolution order:
    1. Local InformationSpace
    2. Explicitly included InformationSpaces
    3. Default InformationSpace
    4. Team/Shared InformationSpace (if configured)

    Attributes:
        space_id: Primary space ID
        included_spaces: Explicitly included space IDs (ordered)
        default_space_id: Default space for common artifacts
        shared_space_id: Team/shared space (optional)
        max_generation_depth: Maximum nesting depth for generators
    """
    space_id: str
    included_spaces: List[str] = field(default_factory=list)
    default_space_id: Optional[str] = None
    shared_space_id: Optional[str] = None
    max_generation_depth: int = 3

    def to_dict(self) -> dict:
        """Convert to dictionary for serialization."""
        return {
            "space_id": self.space_id,
            "included_spaces": self.included_spaces,
            "default_space_id": self.default_space_id,
            "shared_space_id": self.shared_space_id,
            "max_generation_depth": self.max_generation_depth,
        }

    @classmethod
    def from_dict(cls, data: dict) -> "ResolutionConfig":
        """Create from dictionary."""
        return cls(
            space_id=data["space_id"],
            included_spaces=data.get("included_spaces", []),
            default_space_id=data.get("default_space_id"),
            shared_space_id=data.get("shared_space_id"),
            max_generation_depth=data.get("max_generation_depth", 3),
        )


class ResolutionStrategy(ABC):
    """
    Abstract base class for resolution strategies.

    Defines how to search for artifacts across multiple spaces.
    """

    @abstractmethod
    def get_search_order(self, config: ResolutionConfig) -> List[str]:
        """
        Get ordered list of space IDs to search.

        Args:
            config: Resolution configuration

        Returns:
            Ordered list of space IDs (no duplicates)
        """
        pass


class MultiSpaceResolutionStrategy(ResolutionStrategy):
    """
    Multi-space resolution strategy with deterministic search order.

    Implements FR-3.1: Resolution order
    1. Local space
    2. Included spaces (in order)
    3. Default space
    4. Shared space
    """

    def get_search_order(self, config: ResolutionConfig) -> List[str]:
        """
        Get deterministic search order.

        Implements FR-3.1 resolution order:
        1. Local InformationSpace (config.space_id)
        2. Explicitly included InformationSpaces (config.included_spaces)
        3. Default InformationSpace (config.default_space_id)
        4. Team/Shared InformationSpace (config.shared_space_id)

        Removes duplicates while preserving order.

        Args:
            config: Resolution configuration

        Returns:
            Ordered list of unique space IDs
        """
        search_order = []
        seen = set()

        def add_if_not_seen(space_id: Optional[str]) -> None:
            """Add space ID if not None and not already seen."""
            if space_id and space_id not in seen:
                search_order.append(space_id)
                seen.add(space_id)

        # 1. Local space (highest priority)
        add_if_not_seen(config.space_id)

        # 2. Included spaces (in order)
        for included_id in config.included_spaces:
            add_if_not_seen(included_id)

        # 3. Default space
        add_if_not_seen(config.default_space_id)

        # 4. Shared space (lowest priority)
        add_if_not_seen(config.shared_space_id)

        return search_order


class SingleSpaceResolutionStrategy(ResolutionStrategy):
    """
    Simple strategy that only searches the local space.

    Useful for isolated execution or testing.
    """

    def get_search_order(self, config: ResolutionConfig) -> List[str]:
        """
        Return only the local space.

        Args:
            config: Resolution configuration

        Returns:
            List containing only the local space ID
        """
        return [config.space_id]
