"""
Repository interfaces for artifact persistence.

Defines abstract interfaces for artifact storage, enabling
pluggable storage backends.
"""

from abc import ABC, abstractmethod
from typing import List, Optional
from markitect.prompts.models import Artifact, ArtifactType


class RepositoryError(Exception):
    """Base exception for repository errors."""
    pass


class ArtifactNotFoundError(RepositoryError):
    """Raised when an artifact cannot be found."""
    pass


class DuplicateArtifactError(RepositoryError):
    """Raised when attempting to create an artifact with duplicate name."""
    pass


class IArtifactRepository(ABC):
    """
    Abstract interface for artifact persistence.

    Implements FR-1: InformationSpace Addressability
    Provides CRUD operations for artifacts with content digest tracking.
    """

    @abstractmethod
    def create(self, artifact: Artifact) -> Artifact:
        """
        Persist a new artifact.

        Args:
            artifact: Artifact to create

        Returns:
            Created artifact

        Raises:
            DuplicateArtifactError: If artifact with same space_id+name exists
            RepositoryError: On other persistence errors
        """
        pass

    @abstractmethod
    def get_by_id(self, artifact_id: str) -> Optional[Artifact]:
        """
        Retrieve artifact by ID.

        Args:
            artifact_id: Artifact identifier

        Returns:
            Artifact if found, None otherwise
        """
        pass

    @abstractmethod
    def get_by_name(self, space_id: str, name: str) -> Optional[Artifact]:
        """
        Retrieve artifact by space and name.

        Implements FR-1.3: Cross-space artifact lookup

        Args:
            space_id: Space identifier
            name: Artifact name

        Returns:
            Artifact if found, None otherwise
        """
        pass

    @abstractmethod
    def get_by_digest(self, content_digest: str) -> List[Artifact]:
        """
        Find artifacts with matching content digest.

        Implements FR-1.2: Content digest queries

        Args:
            content_digest: SHA-256 digest to match

        Returns:
            List of artifacts with matching digest
        """
        pass

    @abstractmethod
    def list_by_space(
        self,
        space_id: str,
        artifact_type: Optional[ArtifactType] = None,
    ) -> List[Artifact]:
        """
        List all artifacts in a space.

        Args:
            space_id: Space identifier
            artifact_type: Optional type filter

        Returns:
            List of artifacts in space
        """
        pass

    @abstractmethod
    def update(self, artifact: Artifact) -> Artifact:
        """
        Update an existing artifact.

        Updates content digest and modified timestamp.

        Args:
            artifact: Artifact with updated data

        Returns:
            Updated artifact

        Raises:
            ArtifactNotFoundError: If artifact doesn't exist
            RepositoryError: On other persistence errors
        """
        pass

    @abstractmethod
    def delete(self, artifact_id: str) -> bool:
        """
        Delete an artifact.

        Args:
            artifact_id: Artifact identifier

        Returns:
            True if deleted, False if not found
        """
        pass

    @abstractmethod
    def exists(self, space_id: str, name: str) -> bool:
        """
        Check if artifact exists.

        Args:
            space_id: Space identifier
            name: Artifact name

        Returns:
            True if artifact exists
        """
        pass
