"""Protocol contracts for the shared eval subsystem."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable


if TYPE_CHECKING:
    from .schemas import MetricPayload


@runtime_checkable
class ActionTrackerProtocol(Protocol):
    """Minimal tracker interface used by eval flows."""

    def update_status(self, step_code: str, status: str, description: str) -> Any:
        """Persist lifecycle status for a specific evaluation step.

        Args:
            step_code: Evaluation lifecycle step identifier.
            status: Status level such as ``OK`` or ``ERROR``.
            description: Human-readable status description.

        Returns:
            Tracker-specific result, if any.
        """
        ...

    def save_evaluation_results(self, payload: MetricPayload) -> Any:
        """Persist normalized evaluation payload records.

        Args:
            payload: Normalized metric payload records to persist.

        Returns:
            Tracker-specific result, if any.
        """
        ...

    def log_error(self, file_path: str, module: str, message: str) -> Any:
        """Persist an evaluation error entry for observability.

        Args:
            file_path: Source file associated with the error.
            module: Logical module or location string.
            message: Error details to persist.

        Returns:
            Tracker-specific result, if any.
        """
        ...


@runtime_checkable
class ModelLoaderProtocol(Protocol):
    """Runtime model loader callable contract."""

    def __call__(self, action_tracker: Any) -> Any:
        """Load and return a model artifact for the active runtime.

        Args:
            action_tracker: Tracker object used by loader implementation.

        Returns:
            Loaded model artifact.
        """
        ...


@runtime_checkable
class InferenceRunnerProtocol(Protocol):
    """Inference runner callable contract.

    Runners usually return tuples like:
    - (predictions, outputs, targets) for classification
    - (outputs, targets) for detection/segmentation
    """

    def __call__(self, data_loader: Any, model: Any, *args: Any, **kwargs: Any) -> Any:
        """Run model inference over one split and return raw outputs.

        Args:
            data_loader: Split dataloader-like object.
            model: Loaded model artifact to run inference with.
            *args: Additional positional arguments for runner.
            **kwargs: Additional keyword arguments for runner.

        Returns:
            Runner-specific raw output object.
        """
        ...


@runtime_checkable
class ResultFormatterProtocol(Protocol):
    """Result formatter callable contract."""

    def __call__(self, *args: Any, **kwargs: Any) -> MetricPayload:
        """Convert raw inference outputs into normalized payload records.

        Args:
            *args: Positional formatter inputs.
            **kwargs: Keyword formatter inputs.

        Returns:
            Normalized metric payload records.
        """
        ...


@runtime_checkable
class SplitEvaluatorProtocol(Protocol):
    """Single split evaluator callable contract."""

    def __call__(self, split: str, loader: Any) -> MetricPayload:
        """Evaluate a specific split and return normalized metrics payload.

        Args:
            split: Split name such as ``train`` or ``val``.
            loader: Dataloader-like object for the split.

        Returns:
            Normalized metric payload records for the split.
        """
        ...

