from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Callable

from flownet.runtime.topics.topic_identity import canonical_topic_key


@dataclass(frozen=True)
class TopicRoute:
    topic_id: str
    coordinator: str
    affinity_hint: str | None = None


class TopicRouter:
    """
    URI-routing view for topic coordinator placement.

    v1 flat model boundary:
    - this class resolves owner address snapshots from cluster view;
    - it does not own coordinator runtime state or request convergence ledgers.
    """

    def __init__(
        self,
        *,
        cluster_view: Any,
        local_address_fn: Callable[[], str],
    ) -> None:
        self._cluster_view = cluster_view
        self._local_address_fn = local_address_fn

    def resolve(self, topic_id: str, affinity_hint: str | None = None) -> TopicRoute:
        canonical_key = canonical_topic_key(topic_id)
        node = self._cluster_view.resolve_node_for_key(canonical_key, affinity_hint)
        return TopicRoute(topic_id=canonical_key, coordinator=node.address, affinity_hint=affinity_hint)

    def is_local(self, route: TopicRoute) -> bool:
        return route.coordinator == self._local_address_fn()


__all__ = [
    "TopicRouter",
    "TopicRoute",
]
