"""Tunnel - named channel."""

from typing import Iterator

from .message import Message, new_message
from .transport import Transport


class Tunnel:
    def __init__(self, name: str, agent_name: str, transport: Transport):
        self.name = name
        self.agent_name = agent_name
        self.transport = transport

    # --- messaging ---

    def send(self, payload: str, to: str | None = None) -> Message:
        """Mesaj gönder. to=None broadcast, to='x' sadece x'e."""
        msg = new_message(from_=self.agent_name, payload=payload, to=to)
        self.transport.send(self.name, msg)
        return msg

    def receive(self, from_: str | None = None) -> Message | None:
        """Tek mesaj al. from_ ile filtrele, eşleşmeyenler mailbox'ta kalır."""
        return self.transport.receive(self.name, self.agent_name, from_=from_)

    def listen(self, from_: str | None = None) -> Iterator[Message]:
        """Sürekli dinle (blocking generator). from_ ile filtrele."""
        return self.transport.listen(self.name, self.agent_name, from_=from_)

    def wait_for(self, from_: str | None = None) -> Message:
        """Bir mesaj gelene kadar bekle (blocking). from_ ile filtrele."""
        return next(self.transport.listen(self.name, self.agent_name, from_=from_))

    def send_wait(self, payload: str, to: str | None = None, wait_from: str | None = None) -> Message:
        """Gönder + cevap bekle. to ile kime, wait_from ile kimden beklediğini belirt."""
        self.send(payload, to=to)
        return self.wait_for(from_=wait_from or to)

    # --- tunnel management ---

    def promote(self, agent: str) -> None:
        if not self.transport.is_admin(self.name, self.agent_name):
            raise PermissionError(f"{self.agent_name} is not admin")
        self.transport.promote(self.name, agent)

    def demote(self, agent: str) -> None:
        if not self.transport.is_admin(self.name, self.agent_name):
            raise PermissionError(f"{self.agent_name} is not admin")
        self.transport.demote(self.name, agent)

    def leave(self) -> None:
        self.transport.leave(self.name, self.agent_name)

    # --- queries ---

    def members(self) -> list[str]:
        return self.transport.members(self.name)

    def admins(self) -> list[str]:
        return self.transport.admins(self.name)

    def is_admin(self, agent: str | None = None) -> bool:
        return self.transport.is_admin(self.name, agent or self.agent_name)
