"""Actor policy placeholders.

Goal: capture the policy dimensions we may need without committing to exact
defaults yet. The implementation should be minimal and extensible.
See `issues/actor-mailbox-policy-scenarios.md` for the scenario catalog.

Policy responsibilities to clarify
- Admission control: whether a call may enter the mailbox.
- Scheduling: how to choose the next item to execute.
- Concurrency limits: max in-flight calls per actor or per actor group.
- Backpressure response: reject, block, drop, or degrade work.
- Timeout budgets: queue wait vs execution time limits.
- Retry strategy: if, when, and how to retry failures.
- Cancellation: behavior when a caller cancels or when the actor stops.
- Fairness: per-caller or per-actor fairness within a container.
- Observability: what metrics and logs policy should emit.
- Resource awareness: CPU or IO hints to guide scheduling in the future.

Typical application scenarios that drive policy design
- Strict serial actors: only one in-flight call, FIFO ordering.
- Burst traffic: rate limiting to avoid queue growth.
- Control-plane priority: e.g. management calls outrank data-plane work.
- Long IO tasks: need queue time visibility and optional timeout.
- Locality-aware dispatch: same-container actors should be favored when safe.
- Mixed sync/async actors: policy should avoid blocking the user loop.

Non-goals for the first minimal implementation
- Advanced preemption or dynamic priority tuning.
- Distributed quota management across nodes.
- Complex workflow scheduling; keep policy simple and explicit.

Open questions for later
- Whether policy owns "gate" semantics vs mailbox owning it.
- How policy integrates with future concurrency modes (strict vs concurrent).
- Whether policies are per-actor, per-class, or per-flow.

Current direction (draft, not locked)
- Actor config should carry policy choices (queue limits, deadlines, lanes).
- Rejection is a first-class policy outcome that returns exceptions upstream.
- EDF or deadline-aware scheduling is a supported future policy option.
- Backpressure signals can be surfaced to upstream runtime containers.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Protocol

from flownet.runtime.actors.mailbox import ActorCallEnvelope


@dataclass(frozen=True)
class ActorConfig:
    """Actor-level configuration for mailbox/policy settings (draft)."""

    mailbox: dict[str, Any] = field(default_factory=dict)
    policy: dict[str, Any] = field(default_factory=dict)
    metadata: dict[str, Any] = field(default_factory=dict)


class ActorPolicy(Protocol):
    def admit(self, envelope: ActorCallEnvelope) -> bool:
        ...

    def priority(self, envelope: ActorCallEnvelope) -> int | None:
        ...

    def max_inflight(self) -> int | None:
        ...

    def on_reject(self, envelope: ActorCallEnvelope, reason: str) -> None:
        ...

    def on_start(self, envelope: ActorCallEnvelope) -> None:
        ...

    def on_finish(self, envelope: ActorCallEnvelope, ok: bool, latency_ms: float | None) -> None:
        ...

    def on_overload(self, queue_len: int, inflight: int) -> None:
        ...


# TODO: define policy implementations once we decide the minimal execution model
# and admission control behavior.
