"""Domain repository protocol for decision tree nodes.

Defines the ``DecisionRepositoryProtocol`` — the port that the application
layer uses to persist and retrieve decision tree nodes.  Infrastructure
adapters (e.g. the SQLAlchemy-backed ``DecisionRepository``) 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.decision import Decision


@runtime_checkable
class DecisionRepositoryProtocol(Protocol):
    """Port for decision tree node 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, decision: Decision) -> Decision:
        """Persist a new decision and return it.

        Args:
            decision: A ``Decision`` domain model instance.

        Returns:
            The same ``Decision`` after persistence (identity pass-through).
        """
        ...

    def get(self, decision_id: str) -> Decision | None:
        """Retrieve a single decision by its ULID.

        Args:
            decision_id: ULID string of the decision.

        Returns:
            The ``Decision`` domain object, or ``None`` if not found.
        """
        ...

    def get_by_plan(self, plan_id: str) -> list[Decision]:
        """Retrieve all decisions for a plan, ordered by sequence number.

        Args:
            plan_id: ULID of the plan.

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

    def get_tree(self, root_decision_id: str) -> list[Decision]:
        """Retrieve the full decision tree rooted at *root_decision_id*.

        Returns the root followed by its descendants in BFS order.

        Args:
            root_decision_id: ULID of the root decision.

        Returns:
            List of ``Decision`` domain objects in BFS order.
        """
        ...

    def get_path_to_root(self, decision_id: str) -> list[Decision]:
        """Retrieve the path from a decision up to the tree root.

        Args:
            decision_id: ULID of the starting decision.

        Returns:
            List of ``Decision`` objects from the given node to the root.
        """
        ...

    def get_superseded(self, plan_id: str) -> list[Decision]:
        """Retrieve all superseded decisions for a plan.

        Args:
            plan_id: ULID of the plan.

        Returns:
            List of superseded ``Decision`` domain objects.
        """
        ...

    def delete(self, decision_id: str) -> bool:
        """Delete a decision by its ULID.

        Args:
            decision_id: ULID string of the decision to delete.

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