"""Domain repository protocol for namespaced projects.

Defines the ``ProjectRepositoryProtocol`` — the port that the application
layer uses to persist and retrieve namespaced projects.  Infrastructure
adapters (e.g. the SQLAlchemy-backed ``NamespacedProjectRepository``) must
satisfy this protocol.

Based on the clean architecture principle described in the specification:
adapters live at the edge; the domain layer defines the contracts.
"""

from __future__ import annotations

from typing import Protocol, runtime_checkable

from cleveragents.domain.models.core.project import NamespacedProject


@runtime_checkable
class ProjectRepositoryProtocol(Protocol):
    """Port for namespaced project persistence.

    All methods that mutate state flush but do **not** commit; the caller
    or a Unit-of-Work wrapper is responsible for committing the transaction.
    """

    def create(self, project: NamespacedProject) -> NamespacedProject:
        """Persist a new project and return it.

        Args:
            project: A ``NamespacedProject`` domain model instance.

        Returns:
            The same ``NamespacedProject`` after persistence.
        """
        ...

    def get(self, namespaced_name: str) -> NamespacedProject:
        """Retrieve a project by its namespaced name.

        Args:
            namespaced_name: Full ``namespace/name`` string.

        Returns:
            The ``NamespacedProject`` domain object.

        Raises:
            ProjectNotFoundError: If the project does not exist.
        """
        ...

    def list_projects(
        self,
        namespace: str | None = None,
        limit: int = 100,
    ) -> list[NamespacedProject]:
        """List projects with optional namespace filter.

        Args:
            namespace: Optional namespace to filter by.
            limit: Maximum number of results (default 100).

        Returns:
            List of ``NamespacedProject`` domain objects.
        """
        ...

    def update(self, project: NamespacedProject) -> NamespacedProject:
        """Update all mutable fields of an existing project.

        Args:
            project: The ``NamespacedProject`` domain model with updated fields.

        Returns:
            The same ``NamespacedProject`` after persistence.
        """
        ...

    def delete(self, namespaced_name: str) -> bool:
        """Delete a project by its namespaced name.

        Args:
            namespaced_name: Full ``namespace/name`` string.

        Returns:
            ``True`` if the project was deleted, ``False`` if not found.
        """
        ...
