"""
Artifact service for high-level artifact management operations.

This service provides business logic for creating, querying, and updating
artifacts with automatic content digest calculation and change tracking.
"""

from typing import List, Optional
from datetime import datetime

from markitect.prompts.models import (
    Artifact,
    ArtifactType,
    ArtifactMetadata,
    ArtifactReference,
    calculate_content_digest,
)
from markitect.prompts.repositories.interfaces import (
    IArtifactRepository,
    ArtifactNotFoundError,
)


class ArtifactService:
    """
    Service for artifact management operations.

    Provides high-level business logic on top of artifact repository,
    handling content digest calculation, change detection, and cross-space
    artifact resolution.
    """

    def __init__(self, repository: IArtifactRepository):
        """
        Initialize service with repository.

        Args:
            repository: Artifact repository implementation
        """
        self.repository = repository

    def create_artifact(
        self,
        space_id: str,
        name: str,
        content: str,
        artifact_type: ArtifactType = ArtifactType.CONTENT,
        metadata: Optional[ArtifactMetadata] = None,
    ) -> Artifact:
        """
        Create a new artifact with automatic digest calculation.

        Args:
            space_id: ID of containing space
            name: Artifact name
            content: Artifact content
            artifact_type: Type classification
            metadata: Optional metadata

        Returns:
            Created artifact

        Raises:
            DuplicateArtifactError: If artifact already exists
        """
        artifact = Artifact.create(
            space_id=space_id,
            name=name,
            content=content,
            artifact_type=artifact_type,
            metadata=metadata,
        )
        return self.repository.create(artifact)

    def get_artifact(self, artifact_id: str) -> Artifact:
        """
        Retrieve artifact by ID.

        Args:
            artifact_id: Artifact identifier

        Returns:
            Artifact instance

        Raises:
            ArtifactNotFoundError: If artifact doesn't exist
        """
        artifact = self.repository.get_by_id(artifact_id)
        if not artifact:
            raise ArtifactNotFoundError(f"Artifact with ID '{artifact_id}' not found")
        return artifact

    def get_artifact_by_name(self, space_id: str, name: str) -> Artifact:
        """
        Retrieve artifact by space and name.

        Args:
            space_id: Space identifier
            name: Artifact name

        Returns:
            Artifact instance

        Raises:
            ArtifactNotFoundError: If artifact doesn't exist
        """
        artifact = self.repository.get_by_name(space_id, name)
        if not artifact:
            raise ArtifactNotFoundError(
                f"Artifact '{name}' not found in space '{space_id}'"
            )
        return artifact

    def resolve_reference(
        self,
        reference: ArtifactReference,
        search_spaces: List[str],
    ) -> Optional[Artifact]:
        """
        Resolve an artifact reference across multiple spaces.

        Implements FR-1.3: Cross-space artifact references
        Searches spaces in order until artifact is found.

        Args:
            reference: Artifact reference to resolve
            search_spaces: List of space IDs to search in order

        Returns:
            Resolved artifact, or None if not found
        """
        # If reference specifies space, search only that space
        if reference.space_id:
            return self.repository.get_by_name(reference.space_id, reference.name)

        # Search spaces in order
        for space_id in search_spaces:
            artifact = self.repository.get_by_name(space_id, reference.name)
            if artifact:
                # TODO: Handle version constraint when versioning is implemented
                return artifact

        return None

    def update_artifact_content(
        self,
        artifact_id: str,
        new_content: str,
    ) -> Artifact:
        """
        Update artifact content with automatic digest recalculation.

        Args:
            artifact_id: Artifact to update
            new_content: New content

        Returns:
            Updated artifact

        Raises:
            ArtifactNotFoundError: If artifact doesn't exist
        """
        artifact = self.get_artifact(artifact_id)
        artifact.update_content(new_content)
        return self.repository.update(artifact)

    def detect_change(self, artifact_id: str, current_content: str) -> bool:
        """
        Detect if artifact content has changed.

        Args:
            artifact_id: Artifact to check
            current_content: Current content to compare

        Returns:
            True if content has changed

        Raises:
            ArtifactNotFoundError: If artifact doesn't exist
        """
        artifact = self.get_artifact(artifact_id)
        current_digest = calculate_content_digest(current_content)
        return artifact.has_changed(current_digest)

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

        Args:
            space_id: Space identifier
            artifact_type: Optional type filter

        Returns:
            List of artifacts
        """
        return self.repository.list_by_space(space_id, artifact_type)

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

        Useful for finding duplicate content across spaces.

        Args:
            content_digest: SHA-256 digest to match

        Returns:
            List of artifacts with matching digest
        """
        return self.repository.get_by_digest(content_digest)

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

        Args:
            artifact_id: Artifact to delete

        Returns:
            True if deleted, False if not found
        """
        return self.repository.delete(artifact_id)

    def artifact_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
        """
        return self.repository.exists(space_id, name)
